perm filename LSPMN3.RPG[UP,DOC] blob sn#306401 filedate 1977-09-08 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00092 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00004 00002
C00009 00003
C00010 00004
C00014 00005
C00018 00006
C00020 00007
C00025 00008
C00026 00009
C00029 00010
C00033 00011
C00037 00012
C00041 00013
C00046 00014
C00050 00015
C00053 00016
C00054 00017
C00059 00018
C00064 00019
C00069 00020
C00073 00021
C00077 00022
C00081 00023
C00085 00024
C00089 00025
C00093 00026
C00097 00027
C00101 00028
C00103 00029
C00107 00030
C00111 00031
C00115 00032
C00119 00033
C00124 00034
C00127 00035
C00128 00036
C00132 00037
C00137 00038
C00140 00039
C00144 00040
C00146 00041
C00150 00042
C00154 00043
C00158 00044
C00163 00045
C00168 00046
C00173 00047
C00177 00048
C00182 00049
C00187 00050
C00192 00051
C00196 00052
C00201 00053
C00206 00054
C00211 00055
C00216 00056
C00220 00057
C00223 00058
C00226 00059
C00229 00060
C00233 00061
C00237 00062
C00240 00063
C00245 00064
C00249 00065
C00253 00066
C00258 00067
C00262 00068
C00267 00069
C00271 00070
C00275 00071
C00278 00072
C00282 00073
C00286 00074
C00291 00075
C00295 00076
C00297 00077
C00301 00078
C00306 00079
C00310 00080
C00314 00081
C00318 00082
C00322 00083
C00325 00084
C00329 00085
C00333 00086
C00337 00087
C00341 00088
C00345 00089
C00348 00090
C00351 00091
C00353 00092	βββ
C00354 ENDMK
C⊗;

**DRAFT**                          The System                          **DRAFT**


                              Part 3 - The System

                               Table of Contents



1.      The System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-1
1.1     The Top Level Function . . . . . . . . . . . . . . . . . . . . . . . 3-1
1.2     Break Points . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-5
1.3     Control Characters . . . . . . . . . . . . . . . . . . . . . . . . . 3-9
1.4     Exceptional Condition Handling . . . . . . . . . . . . . . . . . . .3-15
1.4.1   The LISP Error System  . . . . . . . . . . . . . . . . . . . . . . .3-15
1.4.2   User Interrupts  . . . . . . . . . . . . . . . . . . . . . . . . . .3-16
1.4.3   Table of User Interrupt Channels . . . . . . . . . . . . . . . . . .3-19
1.4.4   Autoload . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3-25
1.5     Debugging  . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3-27
1.5.1   Binding, Pdl Pointers, and the Evaluator  . . . . . . . . . . . . . 3-27
1.5.2   Functions for Debugging  . . . . . . . . . . . . . . . . . . . . . .3-27
1.5.3   The Trace Package  . . . . . . . . . . . . . . . . . . . . . . . . .3-34
1.5.4   The Stepper  . . . . . . . . . . . . . . . . . . . . . . . . . . . .3-39
1.5.5   The MAR Break Feature  . . . . . . . . . . . . . . . . . . . . . . .3-54
1.6     Storage Management . . . . . . . . . . . . . . . . . . . . . . . . .3-58
1.6.1   Garbage Collection . . . . . . . . . . . . . . . . . . . . . . . . .3-58
1.6.2   Spaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3-59
1.6.3   Storage Control Functions  . . . . . . . . . . . . . . . . . . . . .3-62
1.6.4   Dynamic Space and Pdl Expansion  . . . . . . . . . . . . . . . . . .3-63
1.6.5   Initial Allocation . . . . . . . . . . . . . . . . . . . . . . . . .3-64
1.7     Implementing Subsystems with MACLISP . . . . . . . . . . . . . . . .3-66
1.7.1   Entering LISP  . . . . . . . . . . . . . . . . . . . . . . . . . . .3-66
1.7.2   Saving an Environment  . . . . . . . . . . . . . . . . . . . . . . .3-67
1.7.3   Gaining and Keeping Control  . . . . . . . . . . . . . . . . . . . .3-69
1.7.4   Purity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3-70
1.8     Miscellaneous Functions  . . . . . . . . . . . . . . . . . . . . . .3-75
1.8.1   The Status Functions . . . . . . . . . . . . . . . . . . . . . . . .3-75
1.8.2   Time   . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3-87
1.8.3   Escaping from Lisp . . . . . . . . . . . . . . . . . . . . . . . . .3-87








September 8, 1977                                                       Page 3-1

**DRAFT**                          The System                          **DRAFT**




1.  The System


1.1  The Top Level Function


   The following function is an approximation to what MACLISP does when it is at
its "top level."


































September 8, 1977                    ∪3-1.                              Page 3-1

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**



      (defun standard-top-level nil
             (prog (↑q ↑w ↑r evalhook base ibase ... )
              errs            ;errors, uncaught throws, etc. come here
              ↑g              ;ctrl/G quits come here
                   (reset-bound-vars-and-restore-pdls)
                   (setq ↑g nil)
                   (setq ↑w nil)
                   (setq evalhook nil)
                   (nointerrupt nil)
                   (do-delayed-tty-and-alarmclock-interrupts)
      ;Recall that errors do (setq // errlist) so lambda-binding
      ;  errlist will work properly.  See errlist.
           (mapc (function eval) //)
           (or (status linmode)(terpri))
           (do ((eof (list nil))      ;internal variables
                (prt '* *))
               (nil)          ;do forever (until ↑g or error)
               (setq * (cond ((status toplevel)
                              (eval (status toplevel)))
                             (t (terpri)
                                (cond (prin1 (funcall prin1 prt))
                                      (t (prin1 prt)))
                                (typ 40)
                                (setq (do ((form))(nil)
                                          (setq form (cond (read
                                                            (funcall read eof))
                                                           (t (read eof))))
                                          (or (eq form eof)
                                              (return form))
                                          (terpri)))
                                (and (null read)
                                     (atom -)
                                     (is-a-space (tyipeek))(tyi))
                                ((lambda (+) (eval -))
                                 (prog2 nil + (setq + -)))))))))

which causes a "read-eval-print loop,"  i.e. each S-expression that is  typed in
gets evaluated  and the value  is printed, then  the next S-expression  is read.
Errors and ↑g quit  to top level.  That  is they reinitialize and  then re-enter
this  loop, printing  a *  (but not  destroying the  value of  the  variable *).
Notice that there  is a place in  the middle where the  user can insert  his own


Page 3-2                             ∪3-1.1                    September 8, 1977

**DRAFT**                          The System                          **DRAFT**


special form to be evaluated, using (sstatus toplevel).  It is also  possible to
change just the reader or just  the printer by setq'ing read or prin1.   See the
sstatus function ().

   Variables used by the top-level read-eval-print loop:

*                   VARIABLE

     Contains the  last S-expression  printed out  by the  read-eval-print loop,
     that is, the value of the last  form typed in.  This is true even  after an
     error return to top level, allowing  one to refer to the value  printed out
     before the aborted computation.

+                   VARIABLE

     Contains the last S-expression typed in.  This can be used to edit it or to
     do it  over again.   (Notice how +  is bound  in the  read-eval-print loop.
     This causes + to receive  the correct value even if the  evaluation aborts,
     since an error or ↑g quit will undo the binding.)

-                   VARIABLE

     Contains the  current S-expression  typed in.   This can  be used  by user-
     written error handlers.  It can't be usefully accessed by expressions typed
     in, since it is set before the expression is evaluated.

   By special  arrangement the  values of  +, *,  and -  are preserved  across a
break.  When the break is first entered these have the values for the  last top-
level operation,  during the break  they behave  the same as  at top  level, and
after the break returns they are restored to the values for the top  level loop.
(See break).

/                   VARIABLE

     / is used to temporarily hold the value of errlist when an error returns to
     top level.   This is  so that  lambda-binding errlist  will have  an effect
     (assuming no one lambda-binds /).  Note that / must be typed in as // since
     the slash character is special to the LISP reader.






September 8, 1977                    ∪3-1.1                             Page 3-3

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


errlist             VARIABLE

     The value of errlist  is a list of  forms which are evaluated  when control
     returns to top level either because  of an error or when an  environment is
     initially  started.  It  doesn't apply  if the  environment started  up was
     saved using (suspend).  This feature is used to provide  self-starting LISP
     environments and to provide  special error handling for  subsystems written
     in LISP.

     The symbol errlist  is evaluated to  get the list  of forms in  the binding
     context in which the error occurred, but the forms themselves are evaluated
     in the top-level binding context.

     Example:

        ((lambda (errlist)
                 (putprop 'foo 'bar 'baz)
                 (hack)
                 (remprop 'foo 'baz))
         (cons '(remprop 'foo 'baz)
               errlist))


     The property list of foo will be properly restored even if  the computation
     (hack) is aborted.



















Page 3-4                             ∪3-1.1                    September 8, 1977

**DRAFT**                          The System                          **DRAFT**


1.2  Break Points


   Break points are a mechanism to  allow the user to gain control at  any point
in a program.  Use of the function break causes a read-eval-print  loop, similar
to the one at top level, to be entered.  (This is also called a break loop.) The
user  may  evaluate any  S-expressions,  and  then cause  the  break  to return,
possibly with a value.  Normal execution then proceeds.

   This mechanism can be used to allow for human intervention when an unexpected
condition occurs.  It is used in this way by the MACLISP error system.   A break
loop makes the full power of the LISP interpreter available for debugging.


break               FSUBR

     (break tag pred) evaluates pred, but not tag.  If the value of pred  is not
     nil, the state of  the I/O system is saved,  ";bkpt tag" is typed  out, and
     control  returns to  the terminal.   We say  that a  "break loop"  has been
     entered.  tag may be any object.  It is used only as a message typed out to
     identify  the  break.  It  is  not evaluated.   If  pred is  omitted,  t is
     assumed.  Thus (break tag) is equivalent to (break tag t).  (break tag nil)
     returns nil, and produces no action whatsoever.

     A break loop is a read-eval-print loop similar to top level.  break does an
     errset so that errors cannot cause an abnormal return from the break.  A ↑x
     quit, which causes an ordinary error, will thus return to the break loop if
     used to  interrupt a  computation started in  the break  loop.  A  ↑g quit,
     however, returns back  to LISP top  level, resetting the  environment using
     the errlist, as described above.

     Two forms, $P and (return x), may be typed in a break loop.  If $p is typed
     in, break  returns nil and  execution continues.  This  "$p" is  <dollar> p
     <newline> in  the Multics  implementation, but <altmode>  P <space>  in the
     pdp-10 implementations.  (An atom other than $P can be used to perform this
     function  by changing  the  value of  $P  to another  (non-nil)  atom.  The
     initial value of $P is always $P).

     If (return x) is typed in, break evaluates x and returns that value.  If as
     a  result  of  the  evaluation  of a  typed-in  form,  (throw  x  break) is
     evaluated, break returns x as its value.

     When break returns, the state of the I/O system is restored.

September 8, 1977                    ∪3-1.2                             Page 3-5

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


     An approximate LISP definition of  what break does follows.  Note  that the
     user program can modify this by using (sstatus breaklevel).










































Page 3-6                             ∪3-1.2                    September 8, 1977

**DRAFT**                          The System                          **DRAFT**



(defun break fexpr (x)
       (*break (eval (cadr x)) (car x)) ;note argument reversal

(declare (special ↑q ↑w evalhook * + -))

(defun *break (breakp breakid)
 (and breakp
  (do ((↑q nil) (↑w nil) (evalhook nil) (terpri t) (* *) (+ +) (- -))
      ()                    ;bind key variables
   (terpri msgfiles)        ;msgfiles arguments
   (princ '|;bkpt | msgfiles)   ;  used for
   (princ breakid msgfiles)     ;  Newio only
   (terpri msgfiles)
   (setq + -)               ;last form typed
   (return
    (prog2 nil
     (catch
      (do () (nil)          ;do forever (until throw)
        (errset
          (do ((eof (list nil)) (form))
              (nil)
           (cond ((status breaklevel)
                  (eval (status breaklevel)))
                 (t (setq form (cond (read (funcall read eof))
                                     (t (read eof))))
                    (and (null read)
                         (atom form)
                         (is-a-space (tyipeek))
                         (tyi))
                    (cond ((eq form eof) (terpri))
                          ((and $p (eq form '$p)) (throw nil break))
                          ((eq (car form) 'return)
                           (throw (eval (cadr form)) break))
                          (t (setq - form)
                             (print
                              (setq * ((lambda (+) (eval form))
                                       (prog2 nil + (setq + -)))))
                             (terpri))))))))
     break)
     (terpri)
  ))))


September 8, 1977                    ∪3-1.2                             Page 3-7

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


   The arguments  to break  are a breakpoint  identification and  (optionally) a
break  switch.  If  the break  switch evaluates  to nil,  then nil  is returned.
Otherwise,  the variables  ↑q, ↑w,  evalhook and  terpri are  bound to  nil, the
variables *, +, and - are bound to their current values, and the  message ";bkpt
<breakid>" is printed.  A read-eval-print loop similar to the top level  loop is
then entered.  This break loop is surrounded by an errset.  Errors or  typing ↑x
merely cause the break loop to be re-entered.  The value of  (status breaklevel)
serves a function similar to that of (status toplevel) in the top level loop.

   As each form is read in the default break loop, there are four cases:

     1.  End of file.  For console input this merely indicates rubout beyond the
        number of input characters.  Whether input is from console or elsewhere,
        the (terpri) is done and the reader is entered.

     2.  The  form is the  atom $p  or eq to  the non-nil value  of $P.   nil is
        returned from the break.

     3.  The form is (return  value).  The form value is evaluated  and returned
        from the break.

     4.  Otherwise the form is evaluated and the result printed out in  a manner
        analogous to the  top level read-eval-print  loop.  The variables  +, -,
        and * are updated appropriately.  (Recall, however, that they were bound
        on entry to *break, and so will be restored eventually.)

   The way to return  from a break is  to do a throw  with a tag of  break; this
will return from the catch which surrounds the break loop.  This is how  cases 2
and 3 return their values; case 4 may also cause a return from the break.















Page 3-8                             ∪3-1.2                    September 8, 1977

**DRAFT**                          The System                          **DRAFT**


1.3  Control Characters


   LISP can be directed to take certain actions by entering "control characters"
from the terminal.  The  difference between control characters and  normal input
is that control characters take effect as soon as they are entered  while normal
input only takes effect when LISP asks for it, by use of functions such as read,
or by being in the top level read-eval-print loop or in a break loop.

   Control  characters can  be  typed in  from  the terminal  according  to some
procedure that depends on the  implementation.  A program can mimic  the effects
of the various  control characters by  directly calling the  function associated
with the particular control key (see below).

   Although control characters are usually processed as soon as they  are typed,
they will be delayed if there is a garbage collection in progress or LISP  is in
(nointerrupt tty) mode - see the nointerrupt function.

                    Entering Control Characters in ITS LISP

   In the ITS implementation of MACLISP, control characters are entered by means
of the "CTRL" key  on the terminal.  For  example, CTRL/G is entered  by holding
down "CTRL" and striking the "G" key.  Control characters echo as an  uparrow or
circumflex followed by the character.

   In  Newio, any  character at  all may  be made  an interrupt  character.  See
(sstatus tty) and (sstatus ttyint).

   Interrupt characters  are also  read as  part of  the terminal  input stream.
Normally they are marked in the readtab;e as "worthless" characters.

                  Entering Control Characters in TOPS-10 LISP

   Control characters may be entered in the  same way as in ITS LISP if  LISP is
currently read'ing from the terminal.  If a LISP program is actively running, it
is necessary to first gain  its attention by typing the control-C  character one
or two times, thereby returning to the monitor.  The monitor command REENTER may
then be used  to re-enter the  LISP.  The LISP  will be in  such a state  that a
single control character may be typed in and will take effect.

                  Entering Control Characters in Multics LISP



September 8, 1977                    ∪3-1.3                             Page 3-9

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


   In the Multics implementation of MACLISP, one signals one's desire to enter a
"control" character by  hitting the "attention" key  on the terminal.   (This is
called "break,"  "interrupt," "attn," "quit,"  etc. on different  terminals.  If
Multics is being accessed through the ARPA network, an "interrupt process" (@S S
or @S I P from a TIP) signal should be transmitted.) Lisp responds by typing out
"CTRL/".  Now you may type one letter from the list later in this section, which
will be interpreted to have its "control" meaning.  This control  character must
be followed by a newline.

   It is  also possible to  enter "control" characters  from an  input character
stream, which may have its source at the terminal or in an exec←com, without the
use of the "attention" key.  The desired control character is prefixed by a \036
character.  If two of these prefix characters occur together, one \036 character
is  read  and  no  "control"  action  is  performed.   Otherwise,  the character
following the \036 is processed as a control character, then reading continues.

   Control characters will be accepted  in upper or lower case.   All characters
other than those with defined meanings are rejected with an error message.  Only
one control  character may be  entered at  a time.  When  a "user  interrupt" is
caused, if the  interrupt is not enabled  nothing happens.  If the  interrupt is
enabled, then a user-specified function is called.  The interrupt may be enabled
by binding the appropriate symbol to the function to handle it, or by  using the
(sstatus ttyint) function ().

      Example for Multics LISP:
              (lines containing user input are preceded by ">>>")

      >>>     (defun loop (x) (loop (add1 x)))
              loop
      >>>     (loop 0)
                      function runs for a long time,
      >>>     <ATTN>  then user hits attention button.
      >>>     CTRL/B  LISP types "CTRL/", user types "B"
      >>>     ;bkpt ↑b        system enters break loop
      >>>     x       user looks at value of x
              4067
      >>>     <ATTN>  user hits attention button again
      >>>     CTRL/G  and returns to top level
              Quit
              *




Page 3-10                            ∪3-1.3                    September 8, 1977

**DRAFT**                          The System                          **DRAFT**


   In the following descriptions  of control characters, those which  can always
be processed immediately,  even during a  garbage collection or  in (nointerrupt
'tty) mode, will be indicated by an "!" for the ITS and TOPS-10 implementations,
and an * for the  Multics Implemention.  When appropriate, equivalent  LISP code
is given for producing the same result from a user program.
Control Characters that have initially defined meanings in all implementations:

  B !* runs a break  loop with breakid "↑b"  (see break).  (In the  pdp-10 oldio
          implementation ↑h is used instead of ↑b.) (break ↑b).

  C !* sets  the value  of the  atom ↑d  to nil,  turning off  garbage collector
          messages.  (Not  available in the  TOPS-10 implementation).   (setq ↑d
          nil).

  D !* sets  the  value  of the  atom  ↑d  to t,  turning  on  garbage collector
          messages.  (setq ↑d t)

  G       quits back to the top level of lisp, rebinding all variables  to their
          global values, resetting various system variables, and  evaluating the
          errlist forms.  This is used  to stop a running program when  there is
          no intention of restarting it  again.  (Prints out an *, see  the "top
          level" function,  and the ↑g  function.)  H is  used instead of  ↑b in
          some implementations (see above).

  Q !   sets the  value of  the atom  ↑q to  t, enabling  input from  the source
          selected by the  value of infile, or  selected by use of  the function
          uread.   In the  ITS Newio  implementation, this  is not  an interrupt
          character; instead ↑a is a  macro character, and takes effect  only if
          processed by read.  (setq ↑q t).

  R !   sets the value of the atom ↑r to t, enabling output to  the destinations
          selected by the  value of outfiles, or  selected by use of  the uwrite
          function.  (setq ↑r t).

  S !   turns off  typeout until input  is read.  This  is used to  suppress the
          rest  of  the  typeout from  the  current  request,  without effecting
          typeout from the next request that is typed in.  It is  implemented by
          setting ↑w to  t, then putting a  macro character in the  input stream
          which sets ↑w to nil and does a (terpri) when it is read.

  T !   sets  the  value  of  the  atom  ↑r  to  nil,  disabling  output  to the
          destinations that CTRL/r enables.  (setq ↑r nil).


September 8, 1977                    ∪3-1.3                            Page 3-11

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


  U       causes the current  call to read to  be restarted from  the beginning.
          (Not available in pdp-10 implementations).

  V !   sets the value of the atom  ↑w to nil, enabling output to  the terminal.
          (setq ↑w nil).

  W !   sets the value of  the atom ↑w to  t, disabling output to  the terminal.
          (setq ↑w t)

  X       causes an error which can be caught by errset.  This is a less drastic
          "quit"  than ctrl/G.   If it  is typed  within a  break loop,  it will
          return  no further  than  the break  loop, since  break  uses  errset.
          (error 'quit).

  Z !* On ITS  returns to ITS  command level, i.e.  DDT.  On Multics  returns to
          Multics command level. (start re-enters lisp.) On TOPS-10 goes  to DDT
          if a DDT has been loaded with LISP.
                  The following control characters only exist

          in the Multics implementation.

  . !* does nothing, and is used merely to speed up a slow process by causing an
          interaction.

  ? !* asks the  LISP subsystem what  it is doing:  running, waiting  for input,
          collecting garbage, or running with tty-interrupts masked off.

   The following  control characters only  exist in pdp-10  implementations with
the "moby I/O" capability.  This means the MIT-AI Laboratoray machine.  They are
not  really interrupts,  but occur  only when  processed by  the  terminal input
prescanner (see (sstatus ttyscan)).

  F       cause graphics display slave to seize a display.

  N       turn on display for character output.

  O       turn off display for character output.

  Y       cause display slave to release display.

   The  following control  characters only  work in  the  pdp-10 implementation.
They are not  really interrupts, but occur  only when processed by  the terminal
input prescanner (see (sstatus ttyscan)).

Page 3-12                            ∪3-1.3                    September 8, 1977

**DRAFT**                          The System                          **DRAFT**


  K       redisplay the current input.  This  allows you to get a clean  copy of
          your input after rubouts have been used.

  L       erases the screen if the terminal is a display, then does a control-K.


                          Control-Character Functions


↑g                  SUBR 0 args

     Produces a quit to top level just as if a control-G had been typed.


   These   functions  exist   only  in   the  pdp-10   oldio  and   the  Multics
implementations - they are being phased out.


ioc                 FSUBR

     The argument to ioc is processed  as if it were a "control  character" that
     had been typed  in.  Numbers are taken  as a whole, atomic  symbols' pnames
     are  processed  character  by  character,  except  that  nil   is  ignored.
     Examples:

          (ioc 1) causes user interrupt 1.
          (ioc vt) switches output to the terminal.
          (ioc q) switches input to a file.
          (ioc g) quits back to the top level of lisp.

     If ioc returns, its value is t.


iog                 FSUBR

     iog first saves  the values of  the I/O switches ↑q,  ↑r, and ↑w.   Then it
     processes its first argument the same as ioc.  Next the remaining arguments
     to iog are evaluated, from left to right.  The values of the  variables ↑q,
     ↑r, and ↑w are  restored, and the value  of the last argument  is returned.
     Example:

                         (iog vt (princ "A Message."))


September 8, 1977                    ∪3-1.3                            Page 3-13

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


     gets a message to the console  no matter what the I/O system is  doing.  It
     evaluates to "A Message."

               (iog a x1 x2 ... xn)

     can also be written

               ((lambda (↑q ↑r ↑w)
                        (ioc a)
                        x1
                        x2
                        ...
                        xn)
                nil nil nil)






























Page 3-14                            ∪3-1.3                    September 8, 1977

**DRAFT**                          The System                          **DRAFT**


1.4  Exceptional Condition Handling



1.4.1  The LISP Error System


   The  errors  detected  by  the  LISP  system  are  divided  into  two  types:
correctable and uncorrectable.  The uncorrectable errors will be explained first
since they are simpler.

   An uncorrectable  error is an  error that causes  the evaluation in  which it
occurs to be aborted.  When an uncorrectable error occurs, the first  thing that
happens is the printing of an  error message.  In oldio, the error  message goes
to  the terminal  and nowhere  else (except  echofiles), no  matter how  the I/O
switches and variables are  set.  In newio, the  variable msgfiles is a  list of
the files to which error messages  should be routed; this initially is  just the
terminal.  The error message consists of some explanatory text and (usually) the
object or form that caused the error.

   After the  error message has  been printed, control  is returned to  the most
recent  error-catcher.   There is  an  error-catcher at  top  level,  and error-
catchers are set up by the functions errset (and break, which uses errset).  All
variable  bindings  between the  error-catcher  and the  point  where  the error
occurred are restored.  Thus all  variables are restored to the values  they had
at top level or at the time  the errset was done, unless they were  setq'ed free
(without being bound).

   What happens next depends on how the error-catcher was set up.  At top level,
the  forms on  the errlist  are  evaluated and  the top  level loop  (or  a user
specified top level form) is re-entered.  (The symbol errlist is evaluated prior
to the above restoration of bindings, and saved in the variable /.) If  an error
returns to break, it simply re-enters its read-eval-print loop.  In  the Multics
implementation the fact that break  has caught an error is signalled  by ringing
the bell on the terminal.  If an error returns to errset, errset returns nil and
evaluation proceeds.  If an error returns  to top level, the state of  the world
is reset and * is typed.

   The  above  description is  slightly  simplified.  The  user  can  request an
interrupt  to occur  between the  typing  of the  message and  the  unwinding of
bindings and  return of  control to  an error-catcher.   This user  interrupt is
normally a break loop which allows  the user to examine the values  of variables


September 8, 1977                    ∪3-1.4                            Page 3-15

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


before the bindings are restored, in hope of finding the cause of the error.  If
the error  is going to  return to  top level, the  *rset-trap user  interrupt is
signalled.  In (*rset t) mode a  break loop is entered, but in (*rset  nil) mode
the user interrupt is ignored by  the system supplied handler.  If the  error is
going to return to a break or  an errset, and *rset is non-nil, the  errset user
interrupt is  signalled.  The  initial environment contains  a null  handler for
this interrupt, but the user may supply a break loop or other handler.

   Correctable errors are  errors which may  be corrected by  user intervention.
If such an error is properly  corrected, evaluation will proceed as if  no error
had occurred.  If the option to correct the error is not exercised, this type of
error will be handled the same as an uncorrectable error.

   When a  correctable error occurs,  a user interrupt  is signalled.   See  for
user interrupt  channel assignments for  these errors.  The  initial environment
contains handlers for these errors  which print an error message similar  to the
message printed for an uncorrectable error and then enter a break loop.

   The  argument  passed  to  the  user  interrupt  handler  is  usually  a list
describing the  error.  See section  1.4.2 for details.   If the  user interrupt
handler  is nil,  or if  it returns  a non-list,  the error  is treated  like an
uncorrectable error.  But  if the handler returns  a list, the first  element of
that list is used to correct the error in a way which depends on  the particular
error which occurred.

   If the most recent error-catcher is not top-level, correctable errors will be
treated  as uncorrectable  errors unless  there is  a non-null  handler  for the
errset interrupt.  This is  to prevent multiple confusing "nested"  error breaks
unless the user indicates that he  is sophisticated by setting up a  handler for
the errset interrupt.

   See the functions error, err, and errset.  (The errset handler itself is only
invoked if *rset is non-nil, however.)


1.4.2  User Interrupts


   LISP provides a number of "user interrupts," which are a mechanism by which a
user  procedure  may  temporarily gain  control  when  an  exceptional condition
happens.  The exceptional conditions that use the user interrupt  system include
certain control characters, the alarmclock timers, asynchronous  I/O conditions,


Page 3-16                           ∪3-1.4.1                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


the  garbage  collector,  and  many  of the  errors  that  are  detected  by the
interpreter or by the system  functions.  Errors detected by user  functions can
use this mechanism also.

   The user interrupts are divided  up into several channels.  Each  channel has
associated  with  it  a  service function.   If  the  service  function  is nil,
interrupts on that channel will be ignored.  If the service function is not nil,
it  is a  function which  is called  with one  argument when  the user-interrupt
occurs.  The nature  of the argument depends  on which channel the  interrupt is
on; usually it is an S-expression which can be used to localize the cause of the
interrupt.  Some user interrupts use the value returned by the  service function
to decide what to do about the cause of the interrupt.

   The service  functions for  most user interrupts  are kept  as the  values of
symbols with mnemonic  names.  A list  of these symbols is  on . There  are also
user interrupts  for control  characters.  The service  functions for  these are
declared using (sstatus ttyint).  See .

   The initial values  for the service functions  of the various  interrupts are
provided by the system as break loops for some interrupts and nil for others.

   There  are  some  special considerations  for  user  interrupts  signalled by
correctable  error  conditions.   The  argument to  the  service  function  is a
description of the error whose exact  form is described in the table at  the end
of this section.  If the service function returns nil (or any atom),  the normal
error procedure occurs --  control returns to the  most recent errset or  to top
level if there was no errset.  If the service function returns a list, the first
element of the list is used  to attempt recovery from the error.  The  exact way
that it is used is described in the table.  If recovery is  successful execution
proceeds from the point where  the error occurred.  If recovery  is unsuccessful
another error is signalled.

   Here is an  example of a  user interrupt service  function.  This is  the one
supplied  by the  system for  unbound  variable errors  when the  user  does not
specify one.  Note that  the system-supplied error break  functions consistently
bind  args to  the argument  supplied.  The  user can  check the  value  of this
variable to see what is  wrong.  Note too that the system-supplied  error breaks
restore readtable and obarray before breaking.






September 8, 1977                   ∪3-1.4.2                           Page 3-17

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**



      (defun +internal-ubv-break (args)
             (declare (special args))
             (errprint nil msgfiles)
             ((lambda (readtable obarray)
                      (nointerrupt nil)
                      (break unbnd-vrbl))
              (get 'readtable 'array)
              (get 'obarray 'array)))
      (setq unbnd-vrbl '+internal-ubv-break)


alarmclock          SUBR 2 args

        alarmclock is a function for controlling timers.  It can start  and stop
     two separate  timers; one  is a  real-time timer  (which counts  seconds of
     elapsed time) and the other is a cpu-time timer (which  counts microseconds
     of machine  run time).   The first argument  to alarmclock  indicates which
     timer is being referred to:  it may be the atom time to indicate  the real-
     time timer or the atom runtime to indicate the cpu-time timer.

        The second argument to alarmclock controls what is done to  the selected
     timer.  If it is a positive (non-bignum) number the timer is started.  Thus
     if n is a positive  fixnum or flonum, evaluating (alarmclock 'time  n) sets
     the real-time  timer to go  off in n  seconds, and (alarmclock  'runtime n)
     sets the  cpu-time timer to  go off  in n microseconds.   If the  timer was
     already running the old setting is lost.  Thus at any given time each timer
     can  only  be  running  for   one  alarm,  but  the  two  timers   can  run
     simultaneously.

        If the second argument to alarmclock is not a positive number, the timer
     is shut off,  so (alarmclock x  nil) or (alarmclock x  -1) shuts off  the x
     timer.

        alarmclock returns t if it starts a timer, nil if it shuts it off.

        When  a  timer goes  off,  the alarmclock  user  interrupt  occurs.  The
     service function  is run in  (nointerrupt t)  mode so that  it will  not be
     interrupted  while it  is performing  its service.   If it  wants  to allow
     interrupts, other timers, etc.  it can evaluate (nointerrupt nil).   In any
     case the status of the  nointerrupt flag will be restored when  the service
     function  returns.   The  argument passed  to  the  user  interrupt service


Page 3-18                           ∪3-1.4.2                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


     function is  a list  of one  element, the  atom time  or the  atom runtime,
     depending on the first argument in  the call to alarmclock that set  up the
     timer.  See also the function nointerrupt.


nointerrupt         SUBR 1 arg

        (nointerrupt  t) shuts  off LISP  interrupts.  This  prevents alarmclock
     timers from going  off and prevents the  use of control characters  such as
     CTRL/G and CTRL/B.   Any of these interrupts  that occur are  simply saved.
     (nointerrupt t) mode is used  to protect critical code in  large subsystems
     written in LISP.  A similar  deferral technique is used by the  LISP system
     itself to protect against interrupts in the garbage collector.

        (nointerrupt 'tty) prevents  control characters (typed on  the terminal,
     or "tty") from causing interrupts; however, alarmclock interrupts are still
     allowed.  Any alarmclock interrupts which were saved will now go off.

        (nointerrupt nil) turns interrupts  back on.  Any interrupts  which were
     saved will now get processed.  This is the normal, initial state.

        The result returned from nointerrupt is the previous interrupt  status -
     nil, t, or tty.

        Example:


           ((lambda (oldstatus)
                    <protected code>
                    (nointerrupt oldstatus))
            (nointerrupt t))



1.4.3  Table of User Interrupt Channels


   Each user interrupt channel has a variable whose value is a  functional form,
the service function for that channel.  The name of the interrupt channel is the
same  as the  name of  the  variable.  The  following lists  the  user interrupt
channels in alphabetical order.  The  argument to which the service  function is
applied and the value which it should return are described.  By  convention, all


September 8, 1977                   ∪3-1.4.2                           Page 3-19

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


service functions receive one argument.  Some user interrupts are  initially set
to a system-supplied handler which binds the variable args to this  argument and
enters a break loop.  The name of the interrupt is used as the break identifer.

   Some user interrupts ignore the value returned by the service function, while
others distinguish two cases:  if the value is atomic, the service  function was
not able  to recover from  the condition that  caused the interrupt.   LISP will
take its default  action, such as returning  control to the most  recent errset.
If  the value  is a  list, the  car of  that list  is used  to recover  from the
condition that caused the  interrupt.  It is usually a  new piece of data  to be
used in place of the  one that was being complained  about, or a new form  to be
evaluated in the place of the form that erred.

   If the value of the service-function variable is nil instead of  a functional
form, the user interrupt is considered to be turned off.  The system  behaves as
if the function had run and returned nil.

   Some  user  interrupts  are  asynchronous  in  nature,  and  are  executed in
(nointerrupt t) mode to prevent timing errors.  The interrupt handler may choose
to run in (nointerrupt nil) mode, however, as the initial ↑b handler  does.  The
nointerrupt mode  is restored  after the  handler is  run.  Such  interrupts are
themselves deferred by (nointerrupt t) mode.

alarmclock          VARIABLE

The value of alarmclock is the service function for the user interrupt signalled
when a timer set  up by the alarmclock function  goes off.  The argument  is the
name  of the  timer which  went off,  time or  runtime.  The  returned  value is
ignored.   The  service function  is  executed in  (nointerrupt  t)  mode.  This
interrupt is initially turned off.


autoload            VARIABLE

The  value of  autoload is  the service  function for  the user  interrupt which
provides  automatic  loading  of program  packages  into  the  environment.  The
argument is (function-name  autoload-property).  The returned value  is ignored.
See part 3.4 for details.  This  interrupt is initially set to a  function which
simply loads a file.





Page 3-20                           ∪3-1.4.3                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


cli-message         VARIABLE

The value of cli-message service  handler for the user interrupt  signalled when
another job has interrupted  the LISP job via  the CLI device.  The  argument is
nil and the  returned value is  ignored.  A user handler  is expected to  open a
file on the  CLA device and  read the message from  the other job.   The service
function is  run in (nointerrupt  t) mode.  This  interrupt is  initially turned
off.  Currently, it exists only in the ITS Newio implementation.


errset              VARIABLE

The value  of errset is  the service  function for the  user interrupt  which is
signalled  when an  error is  caught by  an errset  and *rset  is  non-nil.  The
argument  is nil  and the  returned value  is ignored.   This user  interrupt is
initially off.  Turning it on affects the behavior of the error system (see part
3.4).


fail-act            VARIABLE

The value of fail-act  is the service function  for the user interrupt  which is
signalled when any of a large variety of miscellaneous error  conditions occurs.
The argument is a list whose first element is generally a symbol which describes
the type  of error  condition.  The rest  of the  list contains  various objects
related to the error.  The returned  value depends on the error.  These  are not
very standardized and will not  be described here.  This interrupt  is initially
set to a break loop.


gc-daemon           VARIABLE

The value of gc-daemon is the  service function for the user interrupt  which is
signalled after each garbage collection.  The argument is a list of  items; each
item is of the form  (space-name free-before . free-after).  The  returned value
is ignored.  This interrupt is initially turned off.


gc-lossage          VARIABLE

The value of gc-lossage is the service function for the user interrupt  which is
signalled when there is no more available address space or when the Time Sharing


September 8, 1977                   ∪3-1.4.3                           Page 3-21

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


Monitor rejects a request for more memory.  In the Multics implementation, there
is always  enough memory, so  this user interrupt  never occurs.  In  the pdp-10
implementation the argument is the name of the space that lost, and the returned
value is ignored.  This interrupt is initially set to a break loop.


gc-overflow         VARIABLE

The value of gc-overflow is the service function for the user interrupt which is
signalled when a space overflows its gcmax.  (see alloc and (status gcmax).) The
argument  is  the name  of  the space.   The  returned value  is  ignored.  This
interrupt is initially set to a break loop.


io-lossage          VARIABLE

The value of io-lossage is the service function for the user interrupt  which is
signalled when the I/O system encounters an error (for example, a file which was
being opened was not found).  The argument is a list of the name of the function
which erred  and its arguments,  which may have  been standardized  or otherwise
partially digested.  The returned value is a list of a new form to  be evaluated
in place of the call to  the function which erred.  This interrupt  is initially
set to a break loop.


machine-error       VARIABLE

The  value  of machine-error  is  the  service handler  for  the  user interrupt
signalled when some difficulty is experienced by the host machine.   The service
function receives four arguments instead of one.  The first is an  atomic symbol
indicating the type of error:
   eval        illegal machine operation
   examine     attempt to reference non-existent memory
   deposit     attempt to write into read-only memory
   oddp        parity error

The other three arguments are  fixnums which are addresses of  memory locations.
The second is the location of  the error; the third is the program  counter when
the error occurred;  and the fourth  is the JPC (the  program counter as  of the
last jump instruction before the error occurred).  The machine-error handler may
signal a different kind of error or a ↑g quit (see the ↑g function)  if desired,
or enter a break loop.  The  subr function (see ....) may be useful  in decoding


Page 3-22                           ∪3-1.4.3                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


the three fixnum  arguments.  If the handler  returns, the value is  ignored and
the  erroneous operation  is  retried.  If  the user  provides  no machine-error
handler (the  interrupt is initially  turned off), the  error is handled  in the
default manner for the host machine.   On ITS, this puts the user in  DDT.  This
currently exists only in the ITS Newio implementation.


mar-break           VARIABLE

The value of mar-break is  the service handler for the user  interrupt signalled
when the memory location specified  by (sstatus mar) (see...) has  been accessed
in the specified manner.  The argument is nil and the returned value is ignored.
The service  function is  run in  (nointerrupt t)  mode.  Also,  LISP implicitly
performs (sstatus mar  0 nil) before running  the user interrupt; this  helps to
prevent infinite loops.  This  interrupt is initially turned off.   It currently
exists only  in the ITS  Newio implementation. See  ... for more  information on
using this interrupt.


pdl-overflow        VARIABLE

The value of pdl-overflow is  the service function for the user  interrupt which
is signalled when  a pushdown list exceeds  its pdlmax.  (see alloc  and (status
pdlmax).) The  argument is  the spacename  of the  pushdown list.   The returned
value is ignored.  This interrupt is initially set to a break loop.


sys-death           VARIABLE

The value of sys-death is  the service handler for the user  interrupt signalled
when the time-sharing  system is about  to go down,  has been revived  from that
state, or  is being debugged.   The argument  is nil and  the returned  value is
ignored.  A  user handler  may wish  to examine  the result  of (status  its) to
determine the state of the system.  The service function is run  in (nointerrupt
t) mode.  This interrupt is initially turned off.  This currently exists only in
the ITS Newio implementation.


tty-return          VARIABLE

The value of tty-return is the service handler for the user  interrupt signalled
when control of the terminal is returned to the LISP job by its  superior.  This


September 8, 1977                   ∪3-1.4.3                           Page 3-23

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


allows LISP to determine that the display screen may have been changed  by other
jobs.   The argument  is nil  and the  returned value  is ignored.   The service
function is  run in (nointerrupt  t) mode.  This  interrupt is  initially turned
off.  This currently exists only in the ITS Newio implementation.


unbnd-vrbl          VARIABLE

The value of unbnd-vrbl is the service function for the user interrupt  which is
signalled when an attempt  is made to evaluate  an atomic symbol which  does not
have a value (an unbound variable.)  The argument is a list of the  symbol which
could not  be evaluated.  The  returned value is  a list of  a new symbol  to be
evaluated in its place.  This interrupt is initially set to a break loop.


undf-fnctn          VARIABLE

The value of undf-fnctn is the service function for the user interrupt  which is
signalled when an attempt is made to apply an undefined function.   The argument
is a list of the functional form which could not be applied.  The returned value
is  a list  of a  new  functional form  to take  its place.   This  interrupt is
initially set to a break loop.


unseen-go-tag       VARIABLE

The value of unseen-go-tag is the service function for the user  interrupt which
is signalled when  go or throw is  used with a tag  which does not exist  in the
current prog body or in any catch, respectively.  The argument is a list  of the
erroneous tag.  The returned value is a  list of a new tag to replace  it.  This
interrupt is initially set to a break loop.


wrng-no-args        VARIABLE

The value of wrng-no-args is  the service function for the user  interrupt which
is signalled when a function is called with the wrong number of  arguments.  The
argument is a list of two items: First, a list of the function and the arguments
that were passed.  Second, the  lambda-list if the function was  interpreted, or
the same dotted pair as args returns if the function was compiled, or the atom ?
if this information could not be determined.  The returned value is a list  of a
new  form  to be  evaluated  in place  of  the losing  one.   This  interrupt is
initially set to a break loop.

Page 3-24                           ∪3-1.4.3                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


wrng-type-arg       VARIABLE

The value of wrng-type-arg is the service function for the user  interrupt which
is  signalled when  an argument  is passed  to a  system function  which  is not
acceptable to that function.  The argument  is a list of the argument  which was
not accepted.  The  returned value is  a list of a  new argument to  replace it.
That is, directly an  argument, not a form to  be evaluated to get  an argument.
This interrupt is initially set to a break loop.


*rset-trap          VARIABLE

The value of *rset-trap is the service function for the user interrupt  which is
signalled when an error returns  control to top level, just before  the bindings
are  restored.  By  convention, the  handler for  this interrupt  should  not do
anything unless the variable  *rset is non-nil.  This  is so that the  user will
not be bothered unless he has  put lisp in debugging mode.  The argument  is nil
and  the  returned value  is  ignored.  This  interrupt  is initially  set  to a
function which enters a break loop if *rset is non-nil.

   There are  other interrupt handlers  which are associated  with I/O  files or
inferior jobs.  See eoffn, endpagefn, (sstatus ttyint), and create-job.


1.4.4  Autoload


   The autoload feature provides the  ability for a function not present  in the
environment to  be automatically  loaded in  from a  file the  first time  it is
called.  When  eval, apply, funcall,  or the version  of apply used  by compiled
LISP searches the  property list of an  atom looking for a  functional property,
and fails to find one, if  a property is found is under the  indicator autoload,
automatic loading will occur.

   Automatic loading is performed by means of the autoload user  interrupt; thus
the user may assert  any desired degree of  control over it.  When  the autoload
property is encountered, the user interrupt handler is called with one argument,
which is  a dotted pair  whose car is  the atomic symbol  which is  the function
being autoload'ed,  and whose cdr  is the value  of the autoload  property.  The
system-supplied handler for this user interrupt could have been defined by:




September 8, 1977                   ∪3-1.4.3                           Page 3-25

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**



      (setq autoload
            (function (lambda (x) (load (cdr x)) )))

From this one can see that the value of the autoload property should be the name
of the file which contains the definition of the function.  Note:  in  the tops-
10 implementations  the system  autoload handler  presently uses  fasload rather
than load because  the load function requires  the newio feature.   This affects
the form of an autoload property.

   When the interrupt handler returns, it should have put a  functional property
on the property  list of the function  being autoloaded.  If not,  an undf-fnctn
error will occur with a message such as "function undefined after autoload."

   Examples of setting up functions to be autoloaded:

   In the Multics implementation:

   (putprop 'foo ">udd>AutoProg>Library>foo-function" 'autoload)

   In the pdp-10 oldio implementation:

   (putprop 'foo '(foo fasl dsk me) 'autoload)

   In the pdp-10 newio implementation:

   (putprop 400 '((dsk me) foo) 'autoload)

















Page 3-26                           ∪3-1.4.4                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


1.5  Debugging



1.5.1  Binding, Pdl Pointers, and the Evaluator


   The MACLISP evaluator  is based on  a push down  list (pdl), or  stack, which
holds  bindings,  evaluation frames,  and  sundry internal  data.   Bindings are
values of atomic  symbols which are  saved when the  symbols are used  as lambda
variables, prog variables, or  do variables.  Evaluation frames  are constructed
when a non-atomic form is evaluated  or when apply is used.  They  correspond to
function calls.

   As the evaluator recursively evaluates a form, information is pushed onto the
pdl and later popped off.  When the *rset and nouuo flags are t this information
is sufficiently detailed  to be of use  in debugging.  (See the  variables *rset
and nouuo in the next section.)

   A position within the pdl may be named by means of a "pdl pointer",  which is
a  negative  fixnum whose  value  has meaning  to  the evaluator.   nil  is also
accepted as a pdl pointer; it means  the top of the stack, i.e. the  most recent
evaluation.  Note that this is different from nil as a binding  context pointer,
which means  the bottom of  the stack  or the outermost  evaluation.  0  is also
accepted as a pdl pointer; it  designates the frame at the bottom of  the stack.
Pdl pointers may be used  as arguments to several debugging  functions described
in the next section.  Since the fixnum value of a pdl pointer has  only internal
meaning, generally a pdl pointer  cannot be obtained from user input,  except by
the user typing in a pdl pointer chosen from a list of pdl pointers typed out at
him.  The "frame" functions described in the next section may be used  to obtain
pdl pointers.

   An  important thing  to note  about pdl  pointers is  their limited  scope of
validity.  If the  information on the  pdl which is named  by a pdl  pointer has
been popped off since the pdl pointer was created, the pdl pointer no longer has
valid meaning.


1.5.2  Functions for Debugging





September 8, 1977                    ∪3-1.5                            Page 3-27

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


*rset               SUBR 1 arg

        (*rset x) sets the *rset switch to nil if x is nil, or to t if x is non-
     nil,  and returns  the value  it set  it to.   (See below).   This function
     exists primarily for user typing convenience.


*rset               SWITCH

        If  the  *rset switch  is  non-nil,  extra information  is  kept  by the
     interpreter  to  allow  the  debugging  functions,  such  as  baktrace  and
     evalframe, to work.   In addition, the  interpreter will make  extra checks
     such as  checking the number  of arguments  passed to a  subr or  lsubr and
     checking that array subscripts lie within the declared  bounds.  Generally,
     the *rset switch being on means  "I am debugging"; this is known  as "*rset
     mode".  The initial state of the switch is nil.


nouuo               SUBR 1 arg

        (nouuo t) sets the nouuo switch.

        (nouuo nil) turns off the nouuo switch. (This is the initial state.)

        nouuo returns t or nil  according to whether it turned the  nouuo switch
     on or off.   (See below.)  This function  exists primarily for  user typing
     convenience.


nouuo               SWITCH

        If the nouuo switch is on, function calls made by compiled  functions to
     compiled  functions  or  system  functions are  forced  to  go  through the
     interpreter each  time.  This aids  in debugging.  If  the nouuo  switch is
     off, which is the normal case,  compiled calls can be made to  go directly,
     which is much faster.

        The nouuo switch may be turned off at any time.  Each  compiled function
     call will only go through the interpreter once more, at which time  it will
     be linked directly.  If the compiled code has been reloaded into the system
     with the PURE option (see ) then this direct link may be unsnapped  and the
     Interpreter route re-established  by (sstatus uuolinks).  Because  the PURE


Page 3-28                           ∪3-1.5.2                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


     option requires an amount of extra  space and time, it is not  normally on;
     thus links snapped in code reloaded as non-PURE cannot be unlinked.

        The trace  package turns this  switch on when  a function is  traced, in
     order  to  ensure  that  tracing will  work  even  for  compiled functions.
     compiled function  calls which have  been "snapped" to  go directly  do not
     push debugging information  in *rset mode and  cannot be traced.   See also
     (status uuolinks).


baktrace            LSUBR 0 to 2 args

        baktrace  displays  the  stack  of  pending  function  calls.   It gives
     detailed information only in (*rset  t) mode.  The first argument is  a pdl
     pointer, as with evalframe.  If it is omitted, nil is assumed,  which means
     start from the top of the  pdl.  The second argument is the  maximum number
     of lines to be typed; if it is omitted the entire stack is displayed.  (The
     second argument is currently permitted only in the Multics implementation.)
     The information printed by baktrace  is not the same as that  obtained with
     evalframe;  both should  be used  to get  the maximum  amount  of debugging
     information.


baklist             LSUBR 0 to 1 arg

        baklist returns a list  containing the information which  baktrace would
     print.  (This is available only on the pdp-10 implementations.)


errframe            SUBR 1 arg

        errframe returns a  list describing an error  which has been  stacked up
     because of  a user interrupt.   The list has  the form (err  pdlptr message
     bcp), where pdlptr is a number  which describes the location in the  pdl of
     the error,  message is a  character string  which can be  printed out  as a
     description of the error, and bcp is a number which can be used as a second
     argument to eval or a third argument to apply to cause evaluation using the
     bindings in effect just before the error occurred.

        The argument to errframe  can be nil, which  means to find the  error at
     the top of  the stack; i.e. the  most recent error.  It  can also be  a pdl
     ptr,  in which  case  the stack  is  searched downward  from  the indicated


September 8, 1977                   ∪3-1.5.2                           Page 3-29

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


     position.  Thus  if there  are recursive  calls to  the error  handler, the
     second error back down the stack may be found by:

                        (errframe (cadr (errframe nil)))

        The argument  to errframe may  also be a  positive number, which  is the
     negative of a  pdl ptr.  This  means start from  the position in  the stack
     marked by the pdl ptr and search upwards.

        If no error is found, errframe returns nil.


errprint            LSUBR 1 to 2 args

        errprint treats its argument the same as errframe.  The second argument,
     in  newio implementation  only,  is the  file(s)  into which  to  print the
     information  (see  print).   The  message portion  of  the  error  frame is
     princ'ed.  errprint  returns t if  a message  was typed out  and nil  if no
     error frame was found.


evalframe           SUBR 1 arg

        The argument to evalframe  is a pdl ptr,  as with errframe.  The  pdl is
     searched for an evaluation of  a function call, using the same  rules about
     starting point and direction as errframe uses.  evalframe always skips over
     any calls to itself that it finds in the pdl.

        The value is a list (type pdlptr form bcp), where type is eval or apply,
     pdlptr is a pdl pointer to the evaluation in the stack, suitable for use as
     an argument to  evalframe or errframe or  baktrace, form is the  form being
     evaluated or  a list  of the  name of  the function  being applied  and the
     arguments it was applied to, and bcp is a binding context pointer which can
     be used with eval to evaluate something in the binding context  just before
     the evaluation found by evalframe.

        evalframe returns nil if no evaluation can be found.

        evalframe only works in (*rset t) mode, since no extra frame information
     is saved otherwise.




Page 3-30                           ∪3-1.5.2                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


freturn             SUBR 2 args

        (freturn p x)  returns control to the  evaluation designated by  the pdl
     pointer p, and forces it  to return x.  This "non-local-goto"  function can
     be used to do fancy recovery from errors.


evalhook            VARIABLE

        If the value of evalhook is non-null, then special things happen  in the
     evaluator.  When  a form  (even an atom)  is to  be evaluated,  evalhook is
     bound to nil and the functional form which was its value is applied  to one
     argument - the form that was trying to be evaluated.  The value  it returns
     is then returned from the  evaluator.  This feature is used by  the Stepper
     package described later in this section.

        evalhook is bound to nil by break, and setq'ed to nil by errors  that go
     back to top level  and print *.  This  provides the ability to  escape from
     this mode if something bad happens.

        In order not to impair  the efficiency of the LISP  interpreter, several
     restrictions  are imposed  on evalhook.   It only  applies to  evaluation -
     whether in  a read-eval-print loop,  internally in evaluating  arguments in
     forms, or  by explicit  use of  the function  eval.  It  does not  have any
     effect on compiled function references, on use of the function apply, or on
     the "mapping" functions.  Normally  the evaluator does not check  the value
     of evalhook, in order to save time.  To make it check, you must both  be in
     (*rset t) - debugging - mode, and have done (sstatus evalhook t).   Not all
     implementations need  both of those,  but you should  always do both  to be
     sure.  If you  use the Stepper  package, you need  not worry; it  does this
     automatically.


evalhook            LSUBR 2 or 3 args

        (evalhook  form hook)  is a  function which  helps exploit  the evalhook
     feature.   The  form  is  evaluated  with  evalhook  lambda-bound   to  the
     functional  form  hook.   The  checking  of  evalhook  is  bypassed  in the
     evaluation  of form  itself,  but not  in any  subsidiary  evaluations, for
     instance  of  arguments  in  the form.   This  is  like  a "one-instruction
     proceed"  in  a  machine-language debugger.   If  all  three  arguments are
     present, the second is a binding context pointer and is used as  the second
     argument to eval, and the third argument is the hook.

September 8, 1977                   ∪3-1.5.2                           Page 3-31

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


        Example:


           (defun hook fexpr (x)                   ;called as (hook <form>)
                  ((lambda (*rset evalhook)
                           (prog2 (sstatus evalhook t)     ;magic sstatus
                                  (eval (car x))           ;evaluate form
                                  (sstatus evalhook nil))) ;more magic
                   t
                   'hook-function))                ;the hook function

           (defun hook-function (f)
                  (terpri)                 ;print pretty message for input
                  (princ '|form: |)
                  (prin1 f)
                  ((lambda (v)             ;v gets value of form
                           (terpri)        ;pretty output message
                           (princ '|value: |)
                           (prin1 v))
                   (evalhook f 'hook-function)))   ;this is how to eval the form
                                                   ; so as to hook sub-forms


        The following output might be seen:

                form: (cons (car (quote (a . b))) (quote c))
                form: (car (quote (a . b)))
                form: (quote (a . b))
                value: (a . b)
                form: (quote c)
                value: c
                value: ((a . b) . c)
                ((a . b) . c)


The following functions only exist in the Multics implementation.

baktrace1           LSUBR 0 to 2 args

        baktrace1 is the same  as baktrace except that binding  context pointers
     suitable for use with eval and apply are displayed along with  the function
     names.


Page 3-32                           ∪3-1.5.2                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


baktrace2           LSUBR 0 to 2 args

        baktrace2 is the  same as baktrace1  except that pdl  pointers, suitable
     for use with baktrace and evalframe, are displayed along with  the function
     names and binding context pointers.







































September 8, 1977                   ∪3-1.5.2                           Page 3-33

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


1.5.3  The Trace Package


   The LISP trace package provides the ability to perform various actions at the
time a  function is called  and at the  time it returns.   This can be  used for
traditional tracing or for more sophisticated debugging actions.

   The trace  package is  not part of  the initial  environment; however,  it is
automatically  loaded in  on the  first reference  to the  function  trace. (See
autoload.)

   The lisp trace package consists of three main functions, trace,  untrace, and
remtrace, all of which are fexprs.

   A call to trace has the following form:
                              (trace trace←specs)

A trace←spec in turn is either an  atom (the name of the function to  be traced)
or a list:
                      (function-name option1 option2 ...)

where the options are as follows:

break pred      causes  a break  after  printing the  entry trace  (if  any) but
                before applying  the traced  function to  its arguments,  if and
                only if pred evaluates to non-nil.

cond pred       causes trace information to be printed for function entry and/or
                exit if and only if pred evaluates to non-nil.

wherein fn      causes  the function  to  be traced  only when  called  from the
                specified function fn.  The user can give several trace specs to
                trace,  all  specifying  the same  function  but  with different
                wherein options,  so that  the function  is traced  in different
                ways when called from  different functions.  Note that if  fn is
                already being  traced itself, the  wherein option  probably will
                not work as desired.  (Then again, it might.)  Note that  fn may
                not be a compiled function.

argpdl pdl      specifies an atom pdl  whose value trace initially sets  to nil.
                A  list of  the current  recursion level  for the  function, the
                function's name, and a list of the arguments is cons'ed onto the


Page 3-34                           ∪3-1.5.3                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


                pdl when the function is  entered, and cdr'ed back off  when the
                function is exited.  The pdl can be inspected from a breakpoint,
                for example, and  used to determine  the very recent  history of
                the function.  This option  can be used with or  without printed
                trace output.  Each  function can be given  its own pdl,  or one
                pdl may serve several functions.

entry list      specifies a list of arbitrary S-expressions whose values  are to
                be  printed  along  with the  usual  entry-trace.   The  list of
                resultant values, when printed, is preceded by a \\  to separate
                it from the other information.

exit list       similar  to entry,  but specifies  expressions whose  values are
                printed with the exit-trace.  Again, the list of  values printed
                is preceded by \\.

arg                     that the function's arguments, resultant value, both, or
                specify
value                    are to  be traced.   If not  specified, the  default is
                neither
both                   Any "options" following one of these four are  assumed to
                both.
nil                arbitrary  S-expressions whose  values are  to be  printed on
                be
                both  entry  and  exit  to the  function.   However,  if  arg is
                specified, the values are  printed only on entry, and  if value,
                only on exit.  Note that since arg, value, both, and nil swallow
                all  following expressions  for this  purpose, whichever  one is
                used  should  be the  last  option specified.   Any  such values
                printed will  be preceded  by a  // and  will follow  any values
                specified by entry or exit options.

   If the variable arglist is used in any of the expressions given for the cond,
break, entry, or  exit options, or  after the arg,  value, both, or  nil option,
when those expressions are evaluated the value of arglist will effectively  be a
list of the arguments given to the traced function.  Thus

                    (trace (foo break (null (car arglist))))

would cause a break in foo if and only if the first argument to foo is nil.

   Similarly, the variable  fnvalue will effectively  be the resulting  value of
the traced  function.  For obvious  reasons, this should  only be used  with the
exit option.

   The trace specifications may be "factored."  For example,


September 8, 1977                   ∪3-1.5.3                           Page 3-35

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


                     (trace ((foo bar) value wherein baz))

is equivalent to

            (trace (foo value wherein baz) (bar value wherein baz))

   All output printed by trace can be ground into an indented,  readable format,
by simply setting the variable  sprinter to t.  Setting sprinter to  nil changes
the output back  to use the  ordinary print function,  which is faster  and uses
less storage but is less readable for large list structures.


      Examples of the use of trace:

      (1) To trace function foo, printing both arguments on entry and  result on
   exit:
                                  (trace foo)

      or (trace (foo)) or (trace (foo both)).

      (2) To  trace function foo  only when called  from function bar,  and then
   only if (cdr x) is nil:
                 (trace (foo wherein bar cond (null (cdr x))))

      or (trace (foo cond (null (cdr x)) wherein bar))

   As this example shows, the  order of the options makes no  difference, except
   for arg, value, both, or nil, which must be last.

      (3) To trace function quux, printing the resultant value on exiting but no
   arguments on entry, printing  the value of (car  x) on entry, of  foo1, foo2,
   and (foo3 bar) on exit, and of zxcvbnm and (qwerty shrdlu) on both  entry and
   exit:

        (trace (quux entry ((car x)) exit (foo1 foo2 (foo3 bar))
               (qwerty shrdlu)))

      (4)  To trace  function foo  only when  called by  functions bar  and baz,
   printing args on entry and result  on exit, printing the value of  (quux barf
   barph) on exit from foo  when called by baz only, and  conditionally breaking
   when called by bar if a equals b:



Page 3-36                           ∪3-1.5.3                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**



               (trace (foo wherein bar break (equal a b))
                      (foo wherein baz exit ((quux barf barph))))

      (5) To trace  functions phoo and fu,  never printing anything  for either,
   but saving all arguments for both on a common pdl called foopdl, and breaking
   inside phoo if x is nil:

               (trace (phoo argpdl foopdl break (null x) cond nil nil)
                      (fu argpdl foopdl cond nil nil))

      The "cond nil"  prevents anything at all  from being printed.   The second
   nil in each  trace spec specifies  that no args or  value are to  be printed;
   although the cond nil would prevent the printout anyway, specifying  this too
   prevents trace from even setting up the mechanisms to do this.

      trace returns as its  value a list of  names of all functions  traced; for
   any functions traced with the wherein option, say (trace (foo  wherein bar)),
   instead of  returning just  foo it returns  a 3-list  (foo wherein  bar).  If
   trace finds a trace spec it  doesn't like, instead of the function's  name it
   returns a list whose car is ?  and whose cdr is an error message.   The error
   messages are:

(? wherein foo)  trace couldn't find  an expr, fexpr, or macro property  for the
                function specified by the wherein option.

(? argpdl foo)  The  item following the argpdl  option was not a  non-nil atomic
                symbol.

(? foo  not function)  Indicates  that the function  specified to be  traced was
                non-atomic, or  had no  functional property.   (Valid functional
                properties are expr, fexpr, subr, fsubr, lsubr, and macro.)

(? foo)         foo is not a valid option.

   Thus a use of trace such as

                  (trace (foo wherein (nil)) (bar argpdl nil))

would return, without setting up any traces,

                       ((? wherein (nil)) (? argpdl nil))


September 8, 1977                   ∪3-1.5.3                           Page 3-37

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


   If you  attempt to specify  to trace a  function already being  traced, trace
calls untrace before setting up the  new trace.  If an error occurs,  causing (?
something) to be returned, the function for which the error occurred may  or may
not have been untraced.  Beware!

   It is possible to call trace with no arguments.  (trace) evaluates to  a list
of all the functions currently being traced.

   untrace is used to undo the  effects of trace and restore functions  to their
normal, untraced state.  The argument to untrace for a given function  should be
what trace returned for  it; i.e. if trace  returned foo, use (untrace  foo); if
trace returned (foo wherein bar) use (untrace (foo wherein bar)).   untrace will
take multiple specifications, e.g. (untrace foo quux (bar wherein  baz) fuphoo).
Calling untrace  with no  arguments will untrace  all functions  currently being
traced.

   remtrace,  oddly enough,  expunges  the entire  trace package.   It  takes no
arguments.


























Page 3-38                           ∪3-1.5.3                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


1.5.4  The Stepper

                                The Rich Stepper

   The Rich stepper package provides a simple, small debugging capability.

                   How to Use the STEP Facility


   The  LISP  "stepping" package  is  intended  to give  the  LISP  programmer a
facility analogous to  the Instruction Step mode  of running a  machine language
program.  The package contains two compiled functions which are loaded by

                         (FASLOAD STEP FASL DSK LIBLSP)

The user interface is through the function (fexpr) STEP, which sets  switches to
put the LISP interpreter in and out of "stepping" mode.  The basic commands are:


                      (STEP T)        Turn on stepping mode.
                      (STEP NIL)      Turn off stepping mode.
These commands are usually typed at top level, and will take  effect immediately
(i.e. the next S-exp typed in will be evaluated in stepping mode). Also <ctl G>,
in addition to returning to top level, turns off stepping mode.

   In  stepping  mode,  the LISP  evaluator  will  print out  each  S-exp  to be
evaluated before  evaluation, and the  returned value after  evaluation, calling
itself recursively to display the stepped evaulation of each argument, if the S-
exp  is  a function  call.   In stepping  mode,  the evaluator  will  wait after
displaying  each  S-exp  before  evaluation for  a  command  character  from the
console:

                <space>         Continue stepping recursively.

                <rubout>        Show returned value from this level
                                only, and continue stepping upward.

                <cr> or <tab>   Turn off stepping mode. (but continue
                                evaluation without stepping).

                P               Redisplay current form in full
                                (i.e. without prinlevel or prinlength)


September 8, 1977                   ∪3-1.5.4                           Page 3-39

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


                B               Get breakpoint; proceed with alt-P

                M               See advanced features under
                                "stepping macro expansions"

   **************** More Advanced Features *************************

   Selectively turning on STEP:

           (STEP FOO1 FOO2 ...)

   If  this  command  is  typed  at  top  level,  stepping  will   not  commence
immediately, but rather when the  evaluator first encounters a S-expr  whose CAR
is one of FOO1, FOO2, etc.  This form will then display at the console,  and the
evaluator will be in stepping mode waiting for a command character.

   Stepping Macro Expansions:

   If the stepper is  proceeded with a <sp>, it  will not step the  execution of
macro expansions, but will rather just show the result of the macro of expansion
and wait for another command.

   To see the execution of the macro expansion itself, proceed the  stepper with
an M instead of a <sp>.

   Using STEP with breakpoints:

   The above description applies to turning stepping on and off globally  at top
level.  More detail is necessary to use STEP flexibly in and out  of breakpoints
(e.g. together with TRACE).

   If stepping is turned on by (STEP T) at top level, the evaluator will  NOT be
in  stepping  mode  within  a  breakpoint loop.   If  you  wish  to  use stepped
evaluation  within  a break  loop  you must  turn  it on  locally  by  (STEP T).
Conversely, if stepping was  not turned on at top  level and it is turned  on by
(STEP T) in a break loop, it will  NOT be on when return is made from  the break
loop by <alt>P.

   However, executing  (STEP NIL)  inside a  break loop  will turn  off stepping
globally, i.e. within the break loop, and after return has be made by <alt>P.

   The most useful feature is the following, however:


Page 3-40                           ∪3-1.5.4                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


                   (STEP)          Command at top level has no immediate effect.

   After (STEP) has been executed at top level, a subsequent (STEP T)  inside of
a break loop will  have the effect of turning  on stepping mode both  inside the
break loop and globally,  i.e. the evaluator will start  to step as soon  as the
return is made from the break loop by <alt>P.  Thus, for instance, one could set
TRACE  to break  at  some special  place,  and then  use  the break  to  turn on
stepping.

   PRINLEVEL and PRINLENGTH:

   IN the present version, for convenience, PRINLEVEL and PRINLENGTH are lambda-
bound  inside the  hooking function  to 3  and 5  respectively.  These  could be
changed by editing the EXPR code and recompiling.

   When the P command is used, PRINLEVEL and PRINLENGTH are temporarily bound to
NIL, and the toplevel printer (value of atom PRIN1) is used to redisplay current
form.

   Overhead of Stepping:

   If stepping mode has  been turned off by  <ctl G>, the execution  overhead of
having the stepping packing in your LISP is identically NIL.

   If stepping mode has been turned off by (STEP NIL), every call to EVAL incurs
a small  overhead--several machine instructions,  corresponding to  the compiled
code for a simple COND and one function pushdown.

   Running with (STEP) entered at top level is the same overhead-wise as running
with (STEP NIL).

   Stopping stepping by responding  <tab> incurs the same continued  overhead as
(STEP NIL).

   Running with (STEP FOO1  FOO2 ...) can be  more expensive, since a  MEMBER of
the CAR of the  current form into the list  (FOO1 FOO2 ...) is required  at each
call to EVAL.

   Memory-wise, the total compiled stepping package occupies about  423 words of
binary program storage.   Interaction with DEBUG and TRACE:

   To the  best of my  knowledge, the STEP  package has no  special interactions
with DEBUG, TRACE, or any other system packages.

September 8, 1977                   ∪3-1.5.4                           Page 3-41

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


                            The Morganstern Stepper

   The  Morganstern   Stepper  package   provides  debugging   capabilities  for
interpreted lisp programs  that are comparable  to the capabilities  provided by
DDT for assembler code.  These capabilities include:

   1) Single  stepping through  the evaluation of  a function  and over  or into
other interpreted functions, when called, on a selective basis as  determined by
the user.  Each such form and its resulting value may be displayed.

   2) Dynamic  breakpointing on one  or more of  the following  conditions:  the
form or atom about to be evaluated matches a pattern you provide; the form being
evaluated involves a  specified function; a given  atomic symbol evaluates  to a
given value; a given atomic symbol is to be bound in a prog, either type  of do,
or an eval'd  lambda-expression; or upon an  arbitrary condition specified  by a
predicate written as LISP code.

   3) Returning  a different value  for a given  S-expression.  This  allows for
changing the action that would be selected by conditionals in the program and/or
by go's in a prog or do.  You can also go to any tag inside the current prog.

   4) These capabilities may be requested when the program is  initially started
by a top-level form, or they may  be initiated at any other point in  the course
of execution - either  from the terminal while  in a breakpoint, or  directly by
the program.

   The stepper may be invoked initially  by using the function mev as  one would
use eval of one argument; e.g.  (mev '(fcn arg1 arg2)).  From a breakpoint or in
a program, the stepper may be turned on by invoking (hkstart) with no arguments.
It may be turned off by the q command described below, or of course  by control-
G.  After mev  evaluates its argument,  it returns the  value and turns  off the
stepper.  Note that in  the above example the form  given as an argument  to mev
was quoted.  If, say, the value of f was the S-expression (fcn arg1  arg2), then
one could use (mev f) instead.

   At  any  point during  the  stepping, one  may  inspect the  values  of other
variables, and  even reapply mev  to any form.   This may be  done in  either of
three ways.  Each command will be prompted for by //, usually following the last
form printed out.  Any S-expression that  you type which is not recognized  as a
command will be eval'd (within  an errset to catch errors).   Alternatively, you
can use the  e command to eval  any expression, or the  h command to get  a nice
type of control-H break.  (This is  really a control-B break, but it used  to be
control-H so the command happens to be called h.)

Page 3-42                           ∪3-1.5.4                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


   In the ITS  implementation each command must  be followed by a  space (unless
the command  is a  list).  In the  Multics implementation  each command  must be
followed by a newline.  Actually, this depends not on the implementation  but on
(status linmode).  Each form and result which is printed out will be followed by
#number  indicating the  relative level  of evaluation  (i.e. stack  depth since
invocation).

   The primary commands are:

d   (mnemonic for  down) Go  down to  the next  deeper level  of  evaluation and
   display the first  form there before  evaluating it.  E.g.  if the form  is a
   function call, this will display the first argument of the function if it has
   arguments in the  call; otherwise it will  display the first  S-expression of
   the body of the function.  It then prompts for the next command.

e  (eval)  Can be used  to evaluate  an arbitrary expression.   It starts  a new
   line, waits for you to type the expression, then eval's it within  an errset,
   and prints the result.  This  is comparable to just typing the  expression or
   atom after the //, but cannot  be confused with a command, and the  format is
   nicer.

h  (control-H) Enters  a break loop, and  when $p'ed displays the  current form.
   Within the  break, one can  inspect the values  of variables, etc.,  and even
   reapply mev to any form.

n  (next) Display the next form at this level, without showing or inspecting the
   evaluation of the lower levels of the current form.  The value of the current
   form is displayed first.  If you  wish a condition to be tested for  at lower
   levels, use nn instead.

nn Like n but slower since it inspects the lower levels.  Use instead of  n when
   testing for a condition.

u  (up) Go up to the next  higher level of evaluation and show the next  form at
   that  level.  The  form(s)  at the  current  and lower  levels  are evaluated
   without  display.   As  an  example  of its  use,  after  you  have  seen the
   evaluation of the arguments to a function, the next form to be  evaluated, if
   the function  is being  interpreted, will  be the  first S-expression  of the
   function; to avoid seeing how  the function is evaluated internally,  you can
   type u.  Note that the lower  levels are not inspected - thus if  a condition
   is to be tested for at these levels, use uu.



September 8, 1977                   ∪3-1.5.4                           Page 3-43

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


(u num)  If  num is positive  (or zero), forms  are not inspected  nor displayed
   until level num  is returned to.   If negative, it  goes up (abs  num) levels
   relative to the current level.  Thus (u -1) is equivalent to u.

uu Like u but slower.  Use if testing for a condition.

(uu num) Like (u num) but slower.  Use if testing for a condition.

q  (quit) Exit from the stepper.

s  (show  or display  mode)  For  datapoints and  other display  terminals, this
   gives  a nice  easily  read output  of  selected levels  that  constitute the
   context  of the  current evaluation.   Specifically, it  selects  the current
   level for sprinting  (pretty printing) as a  "header", and as you  go deeper,
   the local context  is abbreviate-printed under  this header, and  the current
   output will be sprinted.  s may be used as often as you like.    Headers will
   automatically  be popped  when you  return.  The  command (s  num)  selects a
   particular  level  as a  header.   It and  the  command sn  and  several user
   settable parameters are described in the more detailed section below.

(= s-exp)   The S-expression  is substituted  for the  current form  and another
   command is prompted for (i.e. you can  step into or over the new form  if you
   want to).  When the resulting value is returned it will be as if the original
   form had yielded that value.  For example, you can change the  apparent truth
   or falsity of predicates  or bypass a (go  label), as well as  just returning
   different values for an S-expression.

(cond ...)  Tests  for conditions prior to  evaluation of each future  form, and
   when satisfied will print a  message, display the form, and wait  for another
   command (which may of course be h for a break).  The argument to this cond is
   an  arbitrary S-expression  or symbol  which is  evaluated like  a predicate.
   This is similar to the cond feature of the trace package.

   In specifying the predicate, the  form about to be evaluated may  be obtained
   as the value of the variable %%form.  The expression (hooklevel)  returns the
   relative level of evaluation.  More than one predicate may be given, in which
   case they are or'ed together,  except when two arguments form a  special test
   as described in the more  detailed section below.  The condition  will remain
   active  at all  levels that  are inspected  by the  stepper  until explicitly
   turned off by (cond nil).

   (matchf ...) is a function which will pattern match against the current form.


Page 3-44                           ∪3-1.5.4                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


   It may be used in the predicate of the cond.  (Also see its related use  as a
   command.)  The argument  to matchf is compared  to %%form element  by element
   from left to right, and  succeeds when each element of the  pattern succeeds.
   Of  importance, the  pattern need  not include  the entire  form.   * matches
   anything.   The  procedure is  applied  recursively to  sublists,  unless the
   sublist is  of the  form (#  ...) in  which case  # is  bound to  the current
   element of %%form and  the cdr (not cadr) of  the #-list is evaluated  as the
   test on that element.  Except in  this case, atoms and lists should  be given
   as in the original code  since they are not evaluated.  Some  simple examples
   are:

      (matchf xyz) succeeds if the atom xyz is about to be evaluated.

      (matchf (setq alpha)) succeeds if the atom alpha is about to be setq'd.

      (matchf  (putprop name  * 'source))   succeeds if  the property  source is
         about to be  putprop'd on the  atom pointed to  by (i.e. the  value of)
         name.

      (matchf (setq (#  member # '(alpha beta  s3)))) succeeds if  either alpha,
         beta, or s3 is about to be setq'd.

      (matchf (rplacd * '(* 9))) matches (rplacd (last urlist) '(2 9 4)).

      (matchf ((# member # '(foo  bar)))) succeeds if a function call  to either
         foo or bar is about to  be evaluated (more precisely if the car  of the
         form about to be evaluated is either foo or bar).

nil (cond nil) turns the condition off and saves the current non-nil condition.

(cond) When no argument is given,  the last non-nil condition (which is  the old
   property of  %%cond) is established  as the current  condition (which  is the
   value of %%cond).  (If the previous condition was not nil then it is saved as
   the old property, thus allowing for alternation of two conditions.)

(matchf ...) is equivalent to (cond (matchf ...)), see above.

   The following functions are useful in connection with the stepper.

   (hkstart) will initiate stepping when encountered in a program or  typed from
a breakpoint.  (hkstop) will act like the q command to turn off  stepping. (Also
see below for more info.)


September 8, 1977                   ∪3-1.5.4                           Page 3-45

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


   (mbak) is  a function to  be used like  the lisp system's  (baklist).  (mbak)
strips out from the result of (baklist) those functions that have to do with the
stepper.

   The remainder  of this section  is a complete  list of the  Stepper commands,
which can be used for reference.

   Commands which are not lists must be followed by a space.  You can use rubout
before completing the command (and its space if necessary).   Alternatively, you
may abort the command before completing it by doing control-X.

   Any S-expression that you type which  is not recognized as a command  will be
evaluated (within an errset to catch errors).  Thus you can evaluate any atom or
do any function call simply by  typing it following the prompting // as  long as
it is not interpretable  as one of the commands  below (or nil).  Note  that you
can actually go to  a tag within your prog  simply by typing (go tag)  after the
//.  To evaluate a form which  looks like a command, type (or form)  to evaluate
it, e.g. (or a) evaluates the atom a.  If you want you can even  write functions
which know about the stepper and treat them as commands.

a    (all) Automatically  displays all forms and  values seen by the  stepper at
     all levels.  Typing a space  at any time thereafter will cause  the stepper
     to leave this mode and prompt  for a new command.  If you want  the stepper
     to wait for a command after each form, you can use the d command.

     Commands a  ad (a -)  c and cc  pause after each  new form is  displayed if
     %%ac-sleep is non-nil.  Its value is used as the sleep time in seconds.

ad   (all down) Automatically displays  all forms and values encountered  by the
     stepper in evaluating the current  form (i.e. at deeper levels).   Typing a
     space prior  to completion will  cause the stepper  to leave this  mode and
     prompt  for a  new command.   (Also  see d.)   Sleeps after  each  form, as
     described under the a command.

(a lev)  Automatically displays all forms and values at the indicated  level and
     lower (deeper) levels, turning itself  off when evaluation pops to  a level
     with a  smaller level  number.   Typing  a space  prior to  completion will
     cause the stepper to leave this  mode and prompt for a new  command.  (Also
     see d.)  Sleeps after each form, as described under the a command.

b    Sets a breakpoint  to occur after evaluation  of the current form.   At the
     break, the value to be returned is the value of %%value, and may be changed


Page 3-46                           ∪3-1.5.4                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


     by setq'ing this variable.  The  form that yielded this value is  the value
     of %%form.  Type $p to proceed from the breakpoint.  If you prefer that the
     system wait rather than break see the wtif command.  (b operates  by adding
     the current hooklevel to  %%breaklist.)  You can get automatic  breaking at
     all levels by using (retcond t) or conditional breaking as  described below
     for the (retcond ...) command.

c    (current) Automatically displays all  forms and values at just  the current
     level.   Typing a  space at  any  time during  the display  will  cause the
     stepper to leave this mode and prompt for a new command.  The  stepper does
     not inspect the forms of lower levels - thus if a condition is to be tested
     for at these levels, use  cc.   Sleeps after each form, as  described under
     the a command.

cc   Like c, but inspects the lower levels.

ctog  Flips the %%condnotallow toggle which is initially t, meaning do not allow
     c, m, n, or u commands if a condition is being tested for.  nil means allow
     these anyway.

(cond ...)  Tests for conditions  prior to evaluation of each future  form.  For
     pattern matching against the form  using the matchf function and  for other
     information see the description of (cond ...) above.

special tests for (cond ...) :
     To  aid  the  specification  of common  tests,  the  following  "flags" are
     provided - the same effects could be obtained by inspecting %%form  in your
     own predicate given to cond.  If the first argument to the cond is from the
     set (form  formq bind bindq  atomval atomvalq fcn  fcnq and andq)  then the
     second argument is  used to derive a  test.  This process is  repeated with
     the remaining arguments,  if any.  The  resulting tests, together  with any
     remaining  arguments not  satisfying  this process,  are  effectively or'ed
     together to  derive the  overall condition  (except for  the and  andq flag
     special  tests which  are and'ed).   The arguments  are not  evaluated when
     typed but  are evaluated each  time the condition  is tested.   These flags
     each may be used more than once.

     The meanings of these flags are:

   andq  The next argument is and'ed with the remaining tests, and must  yield a
   non-nil  value for  the  remainder of  the  condition to  succeed.   (See the
   comments for cond in the "complete list of commands" below regarding  the use
   of side effects)

September 8, 1977                   ∪3-1.5.4                           Page 3-47

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


   atomvalq  The next argument  should be a list  of two elements, the  first an
   (unquoted) name of  an atom, and  the second the value  of this atom  for the
   test to succeed.

   bindq  Watch  for the  following (unquoted) atomic  symbol to  be bound  in a
   prog, or in either type of do, or an explicitly evaluated lambda (as distinct
   from an applied lambda or function call).

   fcnq  Watch for the following (unquoted) function name to be seen by  eval as
   the car of the form about to be evaluated.  (This cannot check for applied or
   mapped function calls).

   formq  The following (unquoted) S-expression is to be watched for.  E.g. used
   to check when a particular variable is about to be evaluated.
           These evaluate their  argument each time  the condition is  tested in
  and
           order to get the desired S-expression or atom name, and  then perform
  bind
           like their  "q" counterparts.  These  are particularly useful  if the
  fcn
           flag's argument is the value  of a variable.  (Be sure not  to change
  form
           the  variable's value  accidentally  while the  condition  remains in
  atomval
           effect.)

      As  a simple  example, (cond  fcnq rplacd)  will check  and stop  when the
      function rplacd is about  to be used (i.e. when  it is the the car  of the
      form to be evaluated).

     The  commands c,  m, n,  and  u do  not inspect  all levels,  and  thus the
     condition cannot be tested for at these levels.  You can use cc, nn, mm, or
     uu instead, or  use the ctog  command.  Naturally, condition  testing slows
     the speed  of execution  at levels that  are inspected  by the  stepper but
     which you do not have displayed.

     If you choose to, you can have your predicates produce side-effects such as
     recording information  of value  to you or  setting states  for use  by the
     condition later.  You can  use the and, andq  flags (more than once  if you
     like) to have the expressions executed even upon success, so long  as these
     flags appear first in the condition.  Other conditions are evaluated in the
     order of appearance until the first success is found.

d    (down) Displays the next  level down (as described above also).   Note that
     if the form is an atom, the effect is the same as the n command.   Hence if
     you want the  stepper to display  every form and value,  but to wait  for a
     command after each form, just keep using the d command.


Page 3-48                           ∪3-1.5.4                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


e    (eval) Can be used to evaluate an arbitrary S-expression.  It starts  a new
     line, waits for you to type the expression, evaluates it within  an errset,
     and prints the  result.  Comparable to just  typing the expression  or atom
     after the  //, but cannot  be confused  with a command,  and the  format is
     nicer.

(=  S-exp)  Replaces  the current  form with  the given  S-expression,  and then
     prompts  for another  command, as  described above.   If two  arguments are
     given,  then this  expression will  not be  treated as  a  stepper command,
     rather it will be evaluated (see comments at top of this section).

h    Control-H break  is executed.  The current  form is redisplayed when  $p is
     typed.  The form about to be evaluated is the value of %%form.   Within the
     break, one can inspect the values of variables, etc., and even  reapply mev
     to any form.

k (kill)  Does not evaluate the current form nor display any value. This is good
     for  avoiding  side  effects   if  restepping  through  a   program  again.
     Equivalent to (= nil) followed by m command.

lr (last result) A complete rather than abbreviated printout of the  last result
     is given. (See (p - -) for further information.)

m  Next,  like n  but the result  of the  current form is  not displayed.   If a
     condition is to be tested for at lower levels, use mm.

(matchf ...)  is equivalent to  (cond (matchf ...)), see the the  description of
     (cond ...) above.

mm  Next, like nn but the result of the current form is not displayed.

n  (next) Displays  the value of  the current form  and displays the  next form,
     then awaits  the next command.   Does not inspect  the lower levels.   If a
     condition is to be tested for at lower levels, use nn instead.

nn  Like n but inspects the lower levels.

o  (old)  Does (mev 'last form).  This is useful for seeing how a  form produced
     an unexpected value when  you went over it  with n or nn.   If reevaluating
     the form can produce side effects be careful.  Can be exited from by the xx
     command.  (The old form is the value of %%oldform.)



September 8, 1977                   ∪3-1.5.4                           Page 3-49

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


ol  (old, at current level)  Does (mev 'last form at this level).   Behaves like
     o.  Useful to see the form (at this level) which produced the current value
     - rather than the last form  printed out, as o would yield.  (The  old form
     used here can be obtained by (get %%hooklevel 'oldform).)

p  (print)  Redisplays the  current form.  This is  useful if you wish  to clear
     the screen first with control-L.  Gives typical abbreviated display (see (p
     -  -)), except  has somewhat  different effect  if in  display mode  (see s
     command).  (For  hackers of special  data structures, e.g.  "owl", printing
     will be done with the function which is the value of the atom prin1 if non-
     nil - as also applies to top-level in lisp.  This value of prin1 is checked
     only in the mev function.   Moreover, unless you request lisp not  to "snap
     links" in compiled code, you may have to reload the stepper  after changing
     prin1.

pp (full print) Gives a complete printout of the current form.

ppp  (even better  printout)  Pretty-prints  the current  form using  the sprint
     function.  Uses a lot of screen  in general, and so will turn  on pagepause
     for you.

(p -  -) Resets the  parameters for the  abbreviated printout used  for results,
     forms and the p command.  The first parameter is the prinlevel,  the second
     is the prinlength; both must be given.  If nil is given instead of a number
     no abbreviating is  done with respect to  that parameter; thus (p  nil nil)
     turns  off   abbreviation.   (The  current   settings  are  the   value  of
     %%hookprin.)

q  (quit) Exits  from the stepper.   Previously requested breaks  and conditions
     are disabled, and any non-nil  conditions are saved on the old  property of
     the condition name.  (Control-G also exits as usual.)

s (show or display mode)  For datapoints and other display terminals, this gives
     a nice easily read output of selected levels that constitute the context of
     the current  evaluation.  Specifically,  it selects  the current  level for
     sprinting  as  a "header",  and  as you  go  deeper, the  local  context is
     abbreviate-printed  under  this  header, and  the  current  output  will be
     sprinted.  s may be used as often as you like.   Headers will automatically
     be popped when  you return.  All sprinting  is done with pagepause  on.  If
     control-X is  typed during sprinting,  that expression will  be redisplayed
     using  abbreviated-printing  instead.  When  in  this display  mode,  the p
     command will clear the screen from the last form down, unless  preceeded by


Page 3-50                           ∪3-1.5.4                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


     control-L (or if wrap-around occurred),  in which case the screen  is fully
     redisplayed.  Also see (s arg) for more information and options.

(s arg)  If arg is positive, this selects the form at that level as the "header"
     for s(how) mode.   If negative, it  uses the form  at arg levels  above the
     current  one.  If  arg is  nil,  display mode  is turned  off  (headers are
     remembered though).   (s t)  just turns  display mode  on if  currently off
     using the previously remembered headers  if still applicable; but if  it is
     already on,  this pops the  stack of headers  by one (normally  headers are
     automatically popped when  the level is  returned from).  All  sprinting is
     done  with pagepause  on.   If control-X  is typed  during  sprinting, that
     expression will  be redisplayed  using abbreviated-printing  instead.  Also
     see the sn command.

     Several parameters are  user settable from their  defaults.  %%lowerdisplay
     and %%lowerdisplay-min control the maximum and minimum number of  levels to
     display  below  the  header  (defaults  of  5  and  2).   This  is  done in
     abbreviate-printed form using %%shortprin which is a list of  the prinlevel
     and prinlength (defaults 3 and 3).  Sprinting of forms and results  will be
     abbreviate-sprinted  by  the  msprint  function  if  the  flatsize  of  the
     expression exceeds %%flatsize-max  (default about 450).  The  prinlevel and
     prinlength for the latter are  the list which is the value  of %%sprintabbr
     (default is (7  8)).  If %%flatsize is  nil, full sprinting will  always be
     used;  (if  negative,  abbreviate-sprinting will  always  be  used  so that
     infinite  printing  circular structures  will  sprint  and abbreviate-print
     finitely.  To  turn off  sprinting of results  setq %%result-sprint  to nil
     (default  t).  If  %%mdistitle is  neither  nil nor  a number,  it  will be
     evaluated just after the screen  is cleared, allowing printing of  a title.
     If it is a number,  that number of blank lines  will be left at the  top of
     the screen (also see sviewmsg function below).  If the partial  clearing of
     the screen bothers your eyes, setq'ing %%eyestrain1 to a number  of seconds
     (e.g. 0.5 to 2.0) will slow down the new display depending on the number of
     lines cleared.

sn  Just for  s(how) display  mode.  It  prevents clearing  of the  screen after
     prompting for another command, but  only until the next prompting  // after
     that.  Useful if you want a result to remain displayed a little longer.  If
     you want to prevent clearing of the screen for more than a couple of times,
     use (s nil), then do (s t) when you want to resume display mode.

(retcond  ...)  Tests  for conditions  just after  each form  is  evaluated, and
     breaks when  such condition is  satisfied.  At the  break, the value  to be


September 8, 1977                   ∪3-1.5.4                           Page 3-51

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


     returned  is the  value of  %%value, and  may be  changed by  setq'ing this
     variable.  The form that yielded  this value is the value of  %%form.  Type
     $p to  proceed from the  breakpoint.  The conditions  are specified  as for
     (cond ...).  Note that (retcond t)  will give you a break as each  level is
     popped (returned from),  including levels above  the one where  the request
     was  made.  (retcond  nil)  disables the  retcond.  If  you  prefer waiting
     rather than breaking see the wtif command.

     Two additional flags are available:

   valueq  The  test (equal %%value  next-argument) is performed  as if  it were
   and'ed with the remaining predicates in the condition.

   value  Like valueq but the test is (equal %%value (eval next-argument)).  The
   overall condition is maintained on  the value of the atom %%retcond,  and the
   previous non-nil condition is on the old property of this atom.  If  you want
   both  cond and  retcond conditions  to be  the same  you can  (setq %%retcond
   %%cond).  The value and valueq predicates will be ignored in a (cond ...).

u  (up)  Go up  to next  higher level.   Current and  lower levels  are executed
     without display.  The lower levels are not inspected - thus if  a condition
     is to be tested for at these levels, use uu.  This can be used to  skip the
     display  of  a  function's  internal  evaluation  after  having   seen  the
     arguments, as described in the previous section.

(u num)  If  num is positive  (or zero), forms  are not inspected  nor displayed
     until that level  number is reached.  If  negative, it goes up  this number
     (absolute value) of levels relative  to the current level.  Thus (u  -1) is
     equivalent to u .

uu Like u, but  also inspects lower levels.  Use  if you have a condition  to be
     tested.

(uu num) Like (u  num) but slower.  Use if  testing for a condition.   Note that
     (uu  -999) effectively  means  that you  won't  see any  levels  unless the
     condition in a cond or retcond is satisfied.

wtal  (wait-all)   Flips  a  toggle  which when  on  causes  a  pause  after the
     evaluation of every  form, but before that  value is returned.   The system
     waits for an input character.  Typing y(es), b(reak), or h  (for control-h)
     followed by space will cause a break as would the b command.  Typing just a
     space, or any  other character followed by  a space, will proceed  from the
     pause.  Default is off.

Page 3-52                           ∪3-1.5.4                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


wtif  (wait-if)   Flips a  toggle which  when on  causes requests  by the  b and
     (retcond ...) commands to result in a pause rather than a break.  The pause
     is like that  of the wtal command,  and may be proceeded  by a space;  or a
     break initiated by typing y, b, or h followed by a space.  Default is off.

xx Does a control-X type of  lisp quit.  (A control-X typed after the  // prompt
     will be caught by  an errset.  The xx  command is executed outside  of that
     errset.)

The following other facilities exist:

(gethklevel  num)   This  function  returns  the  S-expression  that  is  on the
     execution stack of the stepper at the given level number (see hkshow).  Can
     be used to get an unsprinted unabbreviated display of the form or to record
     or process the form as you desire, including reapplication of mev to  it in
     the current context.

(hkshow  num)   This function  will  display  previous forms  which  are  on the
     execution stack, as seen by  the stepper while it has been  activated.  The
     previous  num of  levels are  shown,  with the  current form  last.   If no
     argument is given,  then all levels are  shown.  The display is  done under
     the control of prinlevel and prinlength  which are settable by the (p  - -)
     command.  Of course this function can also be used as if it were  a command
     by typing it after the prompting //.

(hksprint num)  This function will sprint the form on the level whose  number is
     given as the argument.  Can also be used as a command.

(hkstart)  Use this function to invoke or reinvoke the stepper from a breakpoint
     or  from  a program  as  described above.   If  used within  a  break, type
     (hkstart) by itself rather than within another S-expression or function, as
     it has to climb the stack from the point of invocation.  If an  argument is
     given  to this  fexpr,  it will  be  evaluated just  prior  to establishing
     stepping, with ↑w bound  to nil, so that  you can print out  information if
     called from a program.

     (It is possible for  the invocation of the  stepper by this method  to have
     limited scope under some circumstances.  Such a boundary would be  a second
     breakpoint higher on the stack or a previously terminated invocation of the
     stepper that  is still  on the stack.   Also if  the program  was initially
     started without  mev, and stepping  is retained thoughout  the rest  of the
     execution, stepping may also remain for forms typed at top level -  to stop
     this just do control-G (or use the q command) .)

September 8, 1977                   ∪3-1.5.4                           Page 3-53

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


(hkstop)  This function  turns off the stepper  whenever executed - in  the same
     manner as the q command would.

hooklist  is  an atom whose  value is  inspected before each  attempt to  read a
     command from the console.   If hooklist is non-nil,  it is assumed to  be a
     list of commands to the stepper - each is printed out when used and treated
     as if it came  from your typein.  hooklist  is also examined at  each level
     that is inspected by the stepper  even if no command reading is  done (e.g.
     nn or uu modes).

(mbak)   This function  gives (baklist)  but without  the stepper  functions, as
     described above.

(mev top-form)  This function initiates stepping and otherwise acts like eval of
     one argument, as described above.

(msprint form)   Gives abbreviated sprinting  of the form.   A second  and third
     numeric argument specify the effective prinlevel and prinlength  here, else
     a list of two numbers found as the value of msprint are used.   The current
     implementation is somewhat slow as  the regular sprint does not  respond to
     standard abbreviating.

(sviewmsg  lineno toeval)   Useful in  conjunction with  s(how) mode.   Puts the
     cursor at the  lineno and evaluates the  second argument, then  returns the
     cursor to its original position.  lineno = 0 means top; if  negative counts
     from bottom, with -1 the  bottom line.  Typically have %%mdistitle  (see (s
     -) command) be a number to  skip lines on top, and use sviewmsg  to display
     your debugging information up there.

   If you really want  specialized processing in particular situations,  you can
inspect  and/or  change %%form  in  a (cond  ...)  predicate, and  %%value  in a
(retcond  ...).  If  %%nohookflag  is t,  form  and value  printout  and command
reading (except from a non-nil hooklist) is inhibited until it is reset  to nil.
Normal command processing is invoked by (%%mhookcom) with %%nohookflag  bound to
nil.  Also described above are %%breaklist, %%cond, %%retcond, and %%hookprin.


1.5.5  The MAR Break Feature


   This feature is currently available only in the ITS implementation.



Page 3-54                           ∪3-1.5.4                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


   The MAR break feature takes advantage of a hardware feature  which interrupts
whenever a given memory location is accessed in a specified way.  It  allows the
LISP user to specify  an interrupt function to  run whenever a variable  or list
cell is modified.   The user must first  "arm" the interrupt by  saying (sstatus
mar cond loc).  cond is the condition on which to interrupt:

          0       Turn off the mar feature.
          1       Interrupt on instruction fetch.
          2       Interrupt on write (modification).
          3       Interrupt on all references.
             (numbers are octal)

On a KL-10 processor, additional conditions are available:

          10       Interrupt on data read.
          11       Interrupt on data read or instruction fetch.
          12       Interrupt on data read or write.
          13       Interrupt on instruction fetch or write.

loc is any s-expression; that cell is the one monitored.


   Example:

              (setq foo (list 'a 'b))
              (sstatus mar 2 foo)
will interrupt if the list cell in foo is ever rplaca'd or rplacd'd.

   An example of the use of the mar-break interrupt:















September 8, 1977                   ∪3-1.5.5                           Page 3-55

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**



      (defun mar-tracer (x)
             ((lambda (val)
                      (sstatus mar 2
                               (get the-mar-variable
                                    'value))
                      (nointerrupt nil)                       ;let endpagfn
                                                              ; interrupts in
                      (terpri msgfiles)
                      (princ '|Now the variable |
                             msgfiles)
                      (prin1 the-mar-variable
                             msgfiles)
                      (princ '| has the value|
                             msgfiles)
                      (prin1 val msgfiles))
              (symeval the-mar-variable)))

      (setq mar-break mar-tracer)

      (defun mar fexpr (x)
             (cond ((null x)(sstatus mar 0 nil))
                   (t (setq the-mar-variable
                            (car x))                          ;make sure the
                                                              ;variable has a
                                                              ;value cell
                      (or (boundp the-mar-variable)
                          (set the-mar-variable
                               nil))
                      (sstatus mar 2
                                (get the-mar-variable
                                     'value)))))
      (mar quux)
      (setq quux 5)

      Now the variable quux has the value 5

      (do ((quuz 0 (+ quux 1))) ((= quux 2))
          (hack quux))

      Now the variable quux has the value 0
      Now the variable quux has the value 1
      Now the variable quux has the value 2

Page 3-56                           ∪3-1.5.5                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


      Now the variable quux has the value 5
      nil
Notice that quux is altered by the  do loop, and also by the restoration  of the
old value 5.  This example is for a KA-10 processor.  On a KL-10  processor, the
interrupt occurs just before a modification or access rather than just after.

   The mar break feature is sometimes used by DDT to debug the LISP  system.  As
long as DDT  and LISP do not  both try to use  the marbreak feature on  the same
LISP at the same time, there should be no problem.  (sstatus mar 0 nil) releases
the mar break feature entirely for use by DDT.

   The suspend function will  attempt to save and  restore the state of  the mar
break feature. If you don't want an armed mar break to persist beyond a  call to
suspend, turn it off first with (sstatus mar 0 nil).

   When a  ↑G quit  (or the ↑g  function) forces  a quit back  to top  level, it
disables  the mar  break before  unwinding variable  bindings and  re-enables it
afterwards.  This is because  during a ↑G quit LISP  may not be in a  good state
for running user interrupt functions.

























September 8, 1977                   ∪3-1.5.5                           Page 3-57

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


1.6  Storage Management


   In MACLISP  storage for  programs and  data is  automatically managed  by the
system.  The casual  user need not concern  himself with storage  management and
need  not  read  this section.   However,  the  user who  is  curious  about the
implementation or who has to construct a subsystem on top of MACLISP may need to
be concerned with how the  internal storage management routines work and  how to
control their general  functioning.  In no case  is it necessary to  control the
exact step by step operations of storage management, but a variety  of functions
are provided to set the  general policy followed by the lisp  storage management
procedures.


1.6.1  Garbage Collection


   Garbage  collection  is the  mechanism  which LISP  uses  to  control storage
allocation.  Whenever LISP feels that too much storage is being used,  a garbage
collection  is  initiated.  The  garbage  collector traces  through  all  the S-
expressions which  can be reached  by car'ing and  cdr'ing from  internal atomic
symbols' values and property  lists, from forms and temporary  results currently
being used by the evaluator, from data used by compiled code, and from the saved
values of bound variables.   All the data which it  finds in this way  is "good"
data,  in that  it is  possible for  it to  be used  again.  Everything  else is
garbage,  which  can never  again  be used  for  anything because  it  cannot be
accessed, so the storage used by it is reclaimed and reused.


gc                  FSUBR

        (gc) causes a garbage collection and returns nil.


gctwa               FSUBR

        gctwa  is used  to control  the garbage  collection of  "truly worthless
     atoms," which are atomic symbols which have no value and no properties, and
     which are not referenced by any list structure, other than the obarray (the
     current obarray if there is more than one).

        (gctwa) causes truly worthless atoms  to be removed on the  next garbage
     collection.

Page 3-58                            ∪3-1.6                    September 8, 1977

**DRAFT**                          The System                          **DRAFT**


        (gctwa t)  causes truly worthless  atoms to be  removed on  each garbage
     collection from now on.  Note:  gctwa does not evaluate its argument.

        (gctwa nil) causes this continual removal of truly worthless atoms to be
     shut  off, but  it  does not  affect  whether the  next  garbage collection
     removes twa's.

        The  value returned  by  gctwa is  a fixnum  which  is 0  if  no garbage
     collection of  truly worthless atoms  will be  done, 1 if  twa's are  to be
     gc'ed on the next  garbage collection, 10 if twa's  are to be gc'ed  on all
     garbage collections, or 11 if both. (These numbers are octal.)


↑d                  SWITCH

        If  the  value  of  ↑d  is  non-nil,  the  garbage  collector  prints an
     informative message  each time  garbage collection  occurs.  In  the pdp-10
     implementation, it also prints a  message when a space is  expanded without
     first doing a complete garbage collection, or when a filen or  inferior job
     is closed because  a file object was  garbage collected.  See  also (status
     gcwho).


See also the user interrupts gc-daemon, gc-overflow, and gc-lossage.


1.6.2  Spaces


   In  MACLISP  the  storage  used for  LISP  objects  is  divided  into several
conceptual subdivisions, called spaces.  Each space contains a different type of
object.  Allocation  proceeds separately  in the  different spaces,  but garbage
collection of  all spaces  occurs together since  an object  in one  space could
contain a pointer to an object in any other space.

   For example, in the pdp-10 implementation, the spaces are as follows:

  LIST    conses (dotted pairs) and lists.

  FIXNUM  fixnums.

  FLONUM  flonums.


September 8, 1977                   ∪3-1.6.1                           Page 3-59

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


  BIGNUM  bignum headers.  Bignums also occupy fixnum and list space.

  SYMBOL  atomic symbols.

  HUNK4   hunks of various sizes.   PDP-10 implementations without hunks  do not
          have these spaces.

  HUNK8

  HUNK16

  ARRAY   "special array cells."

  REGPDL  the "regular" pushdown list.

  SPECPDL the "special" pushdown list, used in binding.

  FXPDL   the fixnum pushdown list, used for temporary numeric values.

  FLPDL   the flonum pushdown list, used for temporary numeric values.

  Binary Program Space  used to hold arrays and compiled code.

  pure LIST, pure FIXNUM, pure FLONUM, pure BIGNUM
          These  spaces are  used to  store "pure"  data of  the  four indicated
          types.  This is a feature used to make subsystems more efficient.  See
          part 6.5.

   In the Multics implementation, the spaces are:

  list    conses (dotted pairs), lists, atomic symbols, bignums, and strings.

  Static Storage   arrays, files, and linkage to compiled code.

  markedpdl  a pushdown list of lisp objects.

  unmarkedpdl  a pushdown list of machine data, not lisp objects.

   Note:  in the  Multics implementation there is  no space for  numbers because
numbers are stored in such a way that they do not take up any extra room.

   The precise spaces available in  a given implementation can be  determined by
using (status spcnames), (status purspcnames), and (status pdlnames).

Page 3-60                           ∪3-1.6.2                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


   Associated  with each  space is  information determining  when an  attempt to
allocate in that space should cause a garbage collection.  The idea is  that one
should allocate for quite a while in  a space, and then decide that it  is worth
the trouble  of doing an  expensive garbage collection  in order to  prevent the
space from using too many bits of actual storage.

   The exact nature  of this information varies  with the space.  In  a pushdown
list  (pdl) space,  all information  must be  stored contiguously,  so  the only
parameter of  interest is how  big the pdl  is.  This can  be measured  in three
ways, so there are three parameters associated with a pdl:

  pdlsize the number of words of valid data in the pdl at the moment.

  pdlmax  the size to  which the pdl may  grow before intervention  is required.
          This is used to detect infinite recursion.

  pdlroom the size beyond which the pdl may not grow no matter what.

   A space such as a list space has three parameters, called the  gcsize, gcmax,
and gcmin.  These are in machine-dependent units of "words".  The gcsize  is the
expected size of the space; as  objects are allocated in the space it  will grow
without garbage collection until it reaches this size.  When it gets  above this
size  garbage collection  will occasionally  be required,  under control  of the
other two parameters.

   The gcmax is the maximum size to which the space should grow; if it gets this
big garbage collections may occur  quite frequently in an attempt to  prevent it
from growing bigger.

   The  gcmin  specifies  the  minimum amount  of  free  space  after  a garbage
collection.  It may be either a  fixnum, which specifies the number of  words to
be free, or a flonum, which specifies the fraction of the space to be free.  The
exact  interpretation of  this  depends on  the implementation.   In  the pdp-10
implementation, which uses free storage lists, the gcmin is the number  of words
which must be on the free storage list after a garbage collection.  If there are
not this many, the  space is grown, except if  its size approaches gcmax  it may
not be grown by  the full amount.  In  the Multics implementation, which  uses a
compacting garbage collector, the criterion for garbage collection is not when a
free list is exhausted but when the space reaches a certain size.  This  size is
the maximum of gcsize and the sum of the size after compactification  plus gcmin
(if it  is a fixnum)  or the size  after compactification times  1/(1-gcmin) (if
gcmin is a flonum.) The effect of this is to allow the same amount of allocation


September 8, 1977                   ∪3-1.6.2                           Page 3-61

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


between garbage collections as there would be in the pdp-10  implementation with
the same gcmin.

   Note that these controls over the sizes of spaces are somewhat inexact, since
there is rounding.  For  instance, the pdp-10 impementation allocates  memory to
spaces  in blocks  512. words.   The Multics  implementation allocates  at least
16384.  words between  garbage collections  and presently  controls the  size of
pushdown lists in blocks of 16. words.

   Some spaces,  such as Binary  Program Space in  the pdp-10  implementation or
Static storage in the Multics implementation are not subject to detailed control
by the user.  The management  of these spaces is entirely  automatic.  Generally
these are spaces where the rate of allocation is fairly placid and most objects,
once allocated, are used forever  and never freed.  Hence the exact  policy used
for storage management in these spaces is not too important.


1.6.3  Storage Control Functions


alloc               SUBR 1 arg

        The alloc  function is  used to  examine and  set parameters  of various
     spaces  having  to do  with  storage management.   To  set  parameters, the
     argument to alloc should be  a list containing an even number  of elements.
     The first  element of  a pair is  the name  of a space,  and the  second is
     either a fixnum  or a 3-list.   A fixnum specifies  the pdlsize (for  a pdl
     space) or the gcsize (for  other spaces.) A 3-list specifies, from  left to
     right,  the  gcsize,  gcmax,  and  gcmin.   nil  means  "don't  change this
     parameter."  Otherwise  a fixnum  must  be supplied,  except  in  the third
     element (the gcmin), where a flonum is acceptable.  A 3-list cannot be used
     with a pdl space.

        An example of this use of alloc, in the pdp-10 Bibop implementation:

          (alloc '(list (30000. 5000. 0.25)
                   fixnum (4000. 7000. nil)
                   regpdl 2000.))

     or, in the Multics implementation:




Page 3-62                           ∪3-1.6.2                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**



          (alloc '(list (30000. nil 0.3)
                   markedpdl 5000.
                   unmarkedpdl 5000.))

        alloc may  also be  called with  an argument  of t,  which causes  it to
     return a list of  all the spaces and their  parameters.  This list is  in a
     form such that it  could be given back to  alloc at some later time  to set
     the parameters back to what they are now.


   See  for  some status  functions which are  related to  the topic  of storage
spaces.


1.6.4  Dynamic Space and Pdl Expansion


   There are several user  interrupts generated by the storage  management.  See
section  1.4 for  a  description of  user interrupts.   The  gc-daemon interrupt
occurs  after each  garbage collection.   The argument  passed to  the gc-daemon
interrupt handler is  a list of  items; each item has  the form (space  before .
after), where space is the name of a space, before indicates the number of cells
free before the garbage collection, and after indicates the number of cells free
afterwards.  (In the Multics implementation, where "free cells" is a meaningless
concept, only the difference of these two numbers is significant.  It represents
the amount of compaction achieved.)

   The gc-lossage interrupt  occurs if the garbage  collector tries to  expand a
space but fails because, for example, the operating system will not give  it any
more storage.  The argument passed to the interrupt service function is the name
of the space that lost.

   The pdl-overflow interrupt is  signalled when some pushdown list  exceeds its
pdlmax.  The  pdlmax is increased  slightly so that  the interrupt  handler will
have room to run.  The argument passed to the interrupt function is the  name of
the pdl  that overflowed.   If the interrupt  function uses  too much  pdl, this
interrupt will occur again.  If this happens enough times, the pdlmax will reach
the pdlroom, there will be no room  in the pdl to take a user interrupt,  and an
uncorrectable error will occur.

   The  interrupt  function  can  decide  to  terminate  the   computation  that


September 8, 1977                   ∪3-1.6.3                           Page 3-63

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


overflowed the pdl,  by doing an (ioc  g) or a (throw),  or it can  increase the
pdlmax by using alloc or  (sstatus pdlmax) and then continue the  computation by
returning.  Note  that unlike  most other user  interrupts, if  the pdl-overflow
interrupt  function returns  nil  (or the  ";bkpt pdl-overflow"  is  $p'ed), the
computation is continued as if the pdl overflow had not occurred.

   The gc-overflow interrupt occurs when  some space (other than a  pdl) exceeds
its gcmax.  This gives  the user a chance to  decide that the size of  the space
should be increased  and the computation continued,  or that something  is wrong
and the computation should be terminated.  The argument passed to  the interrupt
handler  is the  name  of the  space  that overflowed.   The  interrupt handling
function will be able to run  because the garbage collector makes sure  that the
space is sufficiently large before signalling the interrupt, even if  this makes
it become  somewhat larger than  its gcmax.  This  interrupt is similar  to pdl-
overflow; if the interrupt handler  function returns at all, even if  it returns
nil,  the interrupted  computation proceeds.   To terminate  the  computation an
explicit (ioc g), (throw), or (error) must be done.


1.6.5  Initial Allocation


   The pdp-10 implementations  of MACLISP run on  a machine with  a limited-size
address space.  Consequently the allocation of portions of this address space to
different  uses,  such  as  LISP storage  spaces,  becomes  important.   This is
particularly true of implementations  without the "Bibop" feature, which  do not
take advantage of paging.

   When LISP is first entered, it goes through a dialogue with the user known as
"allocation."  Normally the  dialogue simply consists  of the user  declining to
specify anything,  in which  case LISP  chooses suitable  defaults.  If  a large
problem is  to be worked  on, the defaults  may be inappropriate  and it  may be
necessary  to  explicitly allocate  a  larger  amount of  storage.   It  is also
possible for the user's replies to come from a file.

   If LISP is called with a command line from DDT, for example
                            :LISP INDEX LOADER COM:

it reads the indicated  file in the same way  that it would read  .LISP. (INIT).
See below.

   On the other hand,  if LISP is called  without a command line,  it identifies
itself and asks

Page 3-64                           ∪3-1.6.4                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


                                     ALLOC?

Suitable responses  are Y, N,  and CTRL/Q.  There  are other  obscure characters
which can be used  as replies to this  question, but these three  are sufficient
for most purposes.  "N" means that  you do not want to specify  allocation.  You
will  get the  default.   CTRL/Q means  to  read your  initialization  file (see
below.)  "Y"  means  that you  wish  to  go through  the  following  sequence of
questions and answers.

   LISP types out the names of  various spaces and their sizes.  The  first one,
"CORE", is special.   It is not  a space but the  total amount of  address space
desired, and the size  is in pages rather  than words.  After each  question you
may  enter  altmode,  which  terminates the  dialogue  and  gives  the remaining
parameters default values, or space which goes on to the next  question.  Before
your altmode or space you may put a number which is the size you want that space
to be, instead of the number  that was printed.  Again, there are  various other
magic characters besides space  and altmode.  CTRL/G restarts the  dialogue with
the "ALLOC?" question.

   If you reply with a control-Q, it means to read your initialization file.  In
the  ITS implementation,  this is  either udir;  .LISP. (INIT)  or  (INIT); udir
.LISP., where udir is your master sname.  In the TOPS-10 implementation, this is
LISP.INI in the directory you are logged in to.  In the  Multics implementation,
this  hd>start←up.lisp, where  hd  is your  home directory.   Since  the Multics
implementation doesn't have  the allocation dialogue,  this file is  always read
when the lisp command is given with no arguments.

   The first form in  the file should be a  comment which is used to  answer the
questions.  Note that supplying  nonexistent space names in the  comment doesn't
hurt, so you  can use the  same comment for both  Bibop and non-Bibop  LISP.  An
example of the form of this comment is:

               (comment fxs 4000 fixnum 5000 fls 2000
                        symbol 4000 flonum 2000 bignum 1400)

   The remaining forms in the file are simply read and evaluated.








September 8, 1977                   ∪3-1.6.5                           Page 3-65

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


1.7  Implementing Subsystems with MACLISP



1.7.1  Entering LISP


   A subsystem  is an entity  that exists in  most time-sharing systems.   It is
normally a complete world  which the user enters  by typing a command.   He then
has  whatever facilities  the  subsystem offers.   A subsystem  can  be oriented
toward programming, as  the MACLISP subsystem itself  is, or it can  be oriented
toward a particular application, for instance compiling LISP programs, operating
machinery, or solving differential equations.

   MACLISP  is  frequently  used  as  a  base  on  which  to  build  subsystems.
Consequently it has  been equipped with a  number of mechanisms which  allow the
subsystem writer to gain complete control over the operation of MACLISP, make it
possible to  hide the vagaries  of MACLISP  from the naive  user of  a different
subsystem, and provide  increased efficiency in  memory and processor  usage for
heavily-used subsystems.
                         in the Multics implementation

   The  MACLISP subsystem  is entered  by issuing  the lisp  command  at Multics
command level.   If lisp is  called with  no arguments, a  copy of  the standard
initial environment containing  all the system  functions and variables  is made
the current environment.   If the lisp command  is issued with an  argument, the
argument concatenated  with ".sv.lisp"  is the pathname  of a  saved environment
which  is copied  into the  current environment.   This saved  environment would
contain some subsystem, which will receive control.  Additional arguments to the
lisp command in this case are actually arguments to the subsystem.

   Often one constructs  a trivial command for  getting into a  subsystem, which
simply calls the lisp command with the right arguments.

   For  instance,  the  lisp  compiler  subsystem  may  be  entered  through the
lisp←compiler  command,  which  calls  lisp  with  the  pathname  of  the  saved
environment  containing  the  LISP  compiler  as  the  first  argument,  and the
arguments to the lisp←compiler command as the remaining arguments.

   When the standard initial  environment (i.e. the ordinary  MACLISP subsystem)
is  entered, it  checks for  a segment  named start←up.lisp  in the  user's home
directory.  If such a  segment exists, it is  read in, using the  load function.
This facility allows users to "customize" LISP.

Page 3-66                            ∪3-1.7                    September 8, 1977

**DRAFT**                          The System                          **DRAFT**


                           in the ITS implementation

   LISP may be  entered by the  :LISP command.  The  environment set up  by this
command  is  the  standard  initial  environment.   LISP  now  goes  through  an
allocation  dialogue and  optionally reads  your .LISP.  (INIT) file.   See  for
information on this.

   LISP may be entered  by the command :LISP name1  name2 dev dir where  dev and
dir default  to DSK and  the user's directory,  respectively.  In this  case the
file dev:dir;name1 name2 is read in the same way as a .LISP. (INIT)  file.  This
can be used to start up a subsystem.

   It is also possible to build a  subsystem in a LISP, then save it as  TS FOO.
The  :FOO  command  will  now  enter  the  subsystem,  bypassing  the allocation
dialogue.

                         in the TOPS-10 implementation

   LISP may be entered by  the monitor command R LISP.  The  allocation dialogue
(see ) is entered.  Optionally a LISP.INI in the user's directory may be read.

   As in the ITS  implementation, a subsystem can  be saved and then  invoked by
the appropriate R or RUN command.


1.7.2  Saving an Environment


   A subsystem is constructed by  the following procedure.  One starts  with the
ordinary MACLISP  subsystem, and  defines a number  of function  definitions and
variable values.  This creates  an environment which is capable  of implementing
the desired subsystem.  This environment is then saved in a file,  and necessary
mechanisms are set  up so that an  operating-system command can invoke  lisp and
cause  it  to  set  up  the environment  saved  in  the  file.   When  the saved
environment  is invoked  control is  passed to  the functions  in it  which then
proceed to do the business of the subsystem.

   The  exact  way  of  saving the  environment  varies  from  implementation to
implementation.  In the Multics implementation there is a function called save:





September 8, 1977                   ∪3-1.7.1                           Page 3-67

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


save                FSUBR

        (save  foo)  saves  the  current  LISP  environment  in  a   file  named
     foo.sv.lisp in the  working directory.  foo  is not evaluated.   The saving
     operation destroys the working copy of the environment, so when the save is
     complete lisp returns to Multics command level.

        All  variable  values,  file  objects,  array  contents,   and  function
     definitions (and other properties) are saved, but the contents of  the push
     down lists, including previous values of bound variables, cannot  be saved,
     so save should only be used from top level.


   In the pdp-10 implementations there is a function called suspend:

suspend             LSUBR 0 or 1 args

suspend puts  LISP in a  state such that  it can be  :PDUMP'ed (ITS)  or SSAVE'd
(TOPS-10)  and  later  restarted.   When  the  saved  core  image  is restarted,
everything will be the  same as it was  when suspended, and control  will return
from the invocation of suspend.

suspend may be used at any point in a computation, with the restriction  that no
I/O devices other than the terminal may be in use.

In  the ITS  implementation, care  is taken  so that  all subsystems  saved with
suspend from the  same version of  LISP will share the  pure pages of  LISP.  In
addition, all invocations  of a particular subsystem  will share the  pure pages
peculiar to that subsystem.  Declaration of  data to be placed in pure  pages is
described in a later section.

In the TOPS-10  implementation, care is taken  so that all LISPs  and subsystems
saved from LISP will share the same high segment.  There is presently no way for
a subsystem to have its own high segment with additional shared material.

After suspend has prepared the  LISP core-image for dumping, it  returns control
to the operating system so that it can be dumped.

If suspend is given an argument, that argument is explodec'ed and  the resulting
character string  is passed back  to the operating  system as a  command.  (This
doesn't currently work in the TOPS-10 implementation.)

Commonly one will write a setup routine for a subsystem like this:

Page 3-68                           ∪3-1.7.2                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**



     (progn
           (terpri)
           (princ 'options:)
           ... read in options ...
           (terpri)
           (princ 'loading)
           ... load in files of functions ...
           (suspend)
           (start-the-subsystem)
     ))

The subsystem's environment is now ready for dumping.  Alternatively,  one might
write

     (suspend ':PDUMP/ TS/ NSUBSYS/
     :$ALL/ DONE$/
     )

which will do the dump itself and print a message when done.


1.7.3  Gaining and Keeping Control


   In the Multics implementation, when a saved environment is restarted it looks
like  an  error  that returns  to  top  level.  The  forms  in  the  errlist are
evaluated.   These  forms  should  do whatever  is  necessary  to  start  up the
subsystem.  The  arguments to  the command  which invoked  the subsystem  may be
obtained via (status arg) or (status jcl).

   In  the  pdp-10  implementations,  when  a  saved  environment  is  restarted
execution continues  from the  point where  suspend was  called.  The  next form
evaluated should do whatever is necessary to start up the subsystem.  In the ITS
implementation, the arguments  of the command  line which invoked  the subsystem
may be obtained via (status jcl).

   If the subsystem wants to hide the underlying MACLISP from the user, it has a
number of facilities available.   By setting up its own  user-interrupt handlers
it can handle any  LISP errors which occur  itself.  It can replace  the MACLISP
interpretive  interaction loop  with  its own  by using  (sstatus  toplevel) and
(sstatus breaklevel).  It can also provide a totally-different  interaction loop


September 8, 1977                   ∪3-1.7.2                           Page 3-69

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


by not returning control to the  lisp top level when it is started,  but instead
retaining control in its own functions which read and respond to user input.

   It is possible for a subsystem to retain the trappings of MACLISP  but change
the way things read and print.   Macro characters and the readtable can  be used
to change the way input is parsed.  All output by MACLISP (with the exception of
character-string messages) is done through the function prin1, and the subsystem
may redefine this function.  In the Mutlics implementation one  simply redefines
it, but in the  pdp-10 implementations the variable  prin1 must be bound  to the
function which is to substitute for prin1.

   Some subsystems don't do any of this, but simply consist of  standard MACLISP
augmented by some additional  functions which may be  used in forms typed  in at
top level.


1.7.4  Purity


   In  the  pdp-10  implementations,  there  are  some  facilities  which  allow
subsystems to  put their non-changing  data, function definitions,  binary code,
etc.  into pure  pages.  This  decreases  the load  on memory  by  sharing pages
between  multiple  users  of   the  same  subsystem.   (This  applies   only  to
implementations with the "Bibop" feature.)

   There are some extra storage spaces which are used to store pure (unchanging)
LISP  objects.  These  are the  pure list,  pure fixnum,  pure flonum,  and pure
bignum spaces.

purcopy             SUBR 1 arg

        This function makes and returns a copy of its argument in  pure storage.
     This is  primarily of use  in the creation  of large sharable  systems like
     macsyma.   In  implementations  other  than  Bibop  pdp-10 implementations,
     purcopy simply returns its argument.


        There  are  a number  of  features  which control  how  binary  code and
     constants are purified when a compiled program is loaded into lisp.





Page 3-70                           ∪3-1.7.3                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


bporg               VARIABLE

        The value of bporg should always be a fixnum, whose value is the address
     of the  first unused word  of binary program  space.  This  value generally
     should not  be altered by  the user, but  only examined.  bporg  is updated
     whenever binary code is loaded by lap or fasload.


bpend               *** VARIABLE

        This  variable should  also  always have  a  fixnum as  its  value; this
     indicates the first address above the last available word of binary program
     space.  This is updated by many internal lisp routines, such as the garbage
     collector, the array allocator, and lap and fasload.


pagebporg           SUBR no args

        Causes the variable bporg to be adjusted upwards so as to lie on  a page
     boundary.   This  is principally  useful  on ITS  in  conjunction  with the
     function purify.  pagebporg returns the new value of bporg.


purify              SUBR 3 args

        The first two arguments to purify should be fixnums, and delimit a range
     of memory within the lisp system.  The third argument is a flag.  If  it is
     nil,  then the  pages covered  by the  specified range  of memory  are made
     impure, i.e.  writable.   If it is  t, then the  pages are made  pure, i.e.
     read-only and sharable.  If it is bporg, then the pages are also made pure,
     but in addition some work is done  to make sure that no UUO on  those pages
     may ever be  "clobbered".  This option should  always be used if  the pages
     involved contain binary  code loaded by  lap or fasload.   Presently purify
     does nothing in  the TOPS-10 implementation;  it is intended  primarily for
     producing systems built on lisp, such  as Macsyma, in such a way  that pure
     pages  can be  shared between  users.  Example:  The following  sequence of
     commands might be used to produce a sharable system on ITS:







September 8, 1977                   ∪3-1.7.4                           Page 3-71

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**



           (setq lopage (pagebporg))     ;save low page address
           (setq pure t)                 ;specifies pure code
           (fasload funny fasl)          ;load up system
           (fasload weird fasl)
           (uread some lap)
                        ...
           (setq errlist '((terpri)      ;stuff for system startup
                           (princ 'welcome/ to/ supersystem/!)
                           (terpri)))
           (sstatus toplevel             ;set up top level for system
                    '(top-handler))
           (setq hipage (pagebporg))     ;save high page address
           (purify lopage (1- hipage) 'bporg)   ;purify pages
           (suspend ':pdump/ sys:ts/ super/↑M)  ;tell ddt to dump
           (err)                         ;run errlist


pure                VARIABLE

        This variable, initially nil, should be made non-nil by the  user before
     loading binary code which is to  be made pure.  It signals lap  and fasload
     to be circumspect about any UUO's in the code, because pure UUO's cannot be
     clobbered to be PUSHJ's or  JRST's.  lap solves this problem  by clobbering
     the UUO immediately  if the referenced function  is already defined  and is
     itself a subr  rather than an expr;  otherwise the UUO is  made permanently
     unclobberable (i.e. CALL is converted to CALLF, etc.).

        fasload  is somewhat  more  clever: it  too  tries to  clobber  each UUO
     immediately, but  if it  can't it  puts the address  of the  UUO on  a list
     called purclobrl, which is checked at the end of each call to  fasload, and
     each UUO on the list is clobbered at that time, if the appropriate function
     had been loaded by  that call to fasload.   If the function never  does get
     defined, then purify will also check purclobrl and convert each UUO  to its
     permanently unclobberable form.

        If pure has a  fixnum as its value,  then fasload (but not  lap) behaves
     somewhat differently.  If the value of pure (which must be between 1  and 8
     or so) is,  say, 3, then fasload  calls pagebporg, and then  reserves 6=2*3
     pages  of binary  program  space, unless  a  previous call  to  fasload has
     already reserved them (i.e. they are reserved only once).  Thus fasload has
     two sets of 3 pages to work with; we shall call the first set "area  1" and


Page 3-72                           ∪3-1.7.4                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


     the second set  "area 2".  Now whenever  fasload has to load  a clobberable
     UUO, it does not  place it in the code  being loaded, but rather  hashes it
     and places it in area  1 if it was not  there already; a copy is  placed in
     the same relative position in area 2.  Then an XCT instruction  pointing to
     the UUO in area 1 is placed in the binary code.  When all loading  has been
     done, area 2 may be purified, but area 1 may not.

        Now when  running the code,  the UUO's  pointed to by  the XCT's  may be
     clobbered (the pdp-10 lisp UUO  handler is clever about XCT), and  the code
     will run  faster the  second time around  because the  XCT's will  point to
     PUSHJ's.  However, if (sstatus uuolinks)  is called, then area 2  is copied
     back into area  1, effectively unclobbering  all the UUO's.   Naturally, an
     area large  enough to  contain all  the UUO's  should be  reserved; (status
     uuolinks) (q.v.) yields information relevant to this.

        Thus the example given under the purify function above might be modified
     as follows:

           (setq lopage (pagebporg))     ;save low page address
           (setq pure 3)                 ;specifies pure code
           (setq lopage (+ lopage 6000)) ;allow for area 1
           (fasload funny fasl)          ;load up system
           (fasload weird fasl)
           (uread some lap)
                ...
           (setq errlist '((terpri)      ;stuff for system startup
                           (princ 'welcome/ to/ supersystem/!)
                           (terpri)))
           (sstatus toplevel             ;set up top level for system
                    '(top-handler))
           (setq hipage (pagebporg))     ;save high page address
           (purify lopage (1- hipage) 'bporg)   ;purify pages
           (suspend ':pdump/ sys:ts/ super/↑M)  ;tell ddt to dump
           (err)                         ;run errlist


*pure               VARIABLE

        This  variable  controls  automatic  purification  of  S-expressions and
     atomic symbols.  If it is set non-nil (the initial value is nil),  then the
     following  are placed  in pure  storage spaces  instead of  regular storage
     spaces:   pnames  of  atomic  symbols;  list,  fixnum,  flonum,  and bignum


September 8, 1977                   ∪3-1.7.4                           Page 3-73

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


     constants used by code loaded with fasload; properties whose indicators are
     in the  list which is  the value of  the variable putprop  (initially subr,
     fsubr, and lsubr).


purclobrl           VARIABLE

        Used by  fasload to keep  track of UUO's  which are potentially  but not
     immediately clobberable.


        The putprop  and remprop functions  know about purified  property lists.
     If necessary,  they will  copy the  property list  (but not  the properties
     themselves) into non pure storage so that it can be modified.






























Page 3-74                           ∪3-1.7.4                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


1.8  Miscellaneous Functions



1.8.1  The Status Functions


status              FSUBR

   The  status  special  form  is  used  to  get  the  value  of  various system
parameters.  Its first argument,  not evaluated, is an atomic  symbol indicating
which  of its  many  functions status  should  perform.  The  use  of additional
arguments depends on what the first argument is.  These arguments may or may not
be evaluated, depending on the first argument.  If certain  additional arguments
are omitted, a default value,  usually nil is supplied, again depending  on what
the first argument is.  The various status functions are listed below.

sstatus             FSUBR

        The sstatus  special form  is used to  set the  value of  various system
     parameters.  Its arguments are similar to those of status.

These are the things that you can do with status and sstatus:

STATUS FUNCTIONS FOR I/O

tabsize   (status  tabsize) returns  the number  of character  positions assumed
          between tab stops, which depends on the implementation.

newline   (status newline)  returns a  fixnum which  is the  ascii code  for the
          character which  marks the end  of a line  of input.  For  example, (=
          (setq ch (tyi)) (status newline))

charmode  (status charmode f) returns the value of the character-mode switch for
          the file f.   If f is  t or omitted the  terminal is assumed.   If the
          character-mode switch is t  (the normal case for the  terminal) output
          is sent to the  device as soon as it  is generated.  If the  switch is
          nil (the normal case for files other than the terminal) output is held
          until a newline is typed, an error occurs, input is requested,  or the
          buffer becomes  full.  (You can  also cause the  buffer to be  sent by
          using the force-output  function.) This provides  increased efficiency
          at the cost of not immediately seeing all output in some cases.


September 8, 1977                    ∪3-1.8                            Page 3-75

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


          (sstatus charmode x f) sets the character-mode switch of the file f (f
          may be t or omitted to signify the terminal) to x, which may be nil or
          t.  x and f are evaluated.

linmode   (status linmode) reads the  "line mode," and (sstatus linmode  x) sets
          the "line  mode" to  x (t or  nil.) These  functions take  an optional
          extra argument, which is the file whose line mode is  being discussed.
          This defaults to t,  the terminal.  In any  case, this file must  be a
          terminal.  In some implementations the "line mode" may not be changed.
          If the "line mode"  is t, user input is  buffered up a line at  a time
          before being sent to LISP.  The input-editing conventions of  the host
          operating system are used.  If the "line mode" is nil, LISP  sees each
          character  as  it  is   typed  and  applies  its  own   input  editing
          conventions.  This  mode can provide  input facilities more  suited to
          LISP and  possibly better handling  of the terminal,  if it is  a type
          that LISP  knows a great  deal about.  However,  it uses  more machine
          resources.  It is possible for  a user program to take  direct control
          of the terminal when the "line mode" is nil, however this  may require
          knowledge  of the  undocumented (sstatus  tty) function.   The Multics
          implementation always operates with a "line mode" of t.  See  also the
          (sstatus ttyscan) function below.

ttyint    (sstatus ttyint char  func file) turns  on a tty  interrupt character.
          When  the character  char is  typed on  the input  tty file,  the LISP
          program will be interrupted and  the function func will be  applied to
          two arguments -  file and char.  If  file is omitted, t,  the ordinary
          tty input, is assumed.  The char may be either a character object or a
          fixnum (ascii code).   Any of the 128.  ascii characters may  be used.
          The func may be either an ordinary functional form or a  fixnum, which
          means the default  system action for  that character.  For  instance a
          func of 7 means  quit back to the  top level of lisp  (control-G).  If
          func is nil, the  char is made non-interrupting.  All  three arguments
          are evaluated.

          (status ttyint char file) returns func, the interrupt function for the
          character char on the tty file.  file may be omitted.  It  defaults to
          t.

ttycons   (sstatus ttycons tty1 tty2) binds  two tty files into a  console.  One
          should be an input tty and  the other an output tty.  If tty1  or tty2
          is t,  it will be  taken as the  appropriate direction of  the regular
          terminal.  The binding into  a console is basically used  for purposes


Page 3-76                           ∪3-1.8.1                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


          of echoing.  In addition,  interrupt characters typed on an  input tty
          file should affect  the output on  its corresponding output  tty file,
          not on some other tty.

          To put echoing at the bottom of the screen, distinct from output,

               (sstatus ttycons t
                                (open 'tty: '(echo out tty)))

          which conses tty input with a  new tty output channel which is  set to
          go to the echo area at the bottom of the screen.

          (status ttycons tty1) returns the other tty file which is bound into a
          console with tty1, or nil if there is none.

filemode  (status filemode  file) =>  (open-mode-list .  internal-cruft).  open-
          mode-list  is  a  suitable  second  argument  for  the  open function.
          internal-cruft is a list of implementation-dependent information which
          may sometimes be needed by special programs.

          The following  symbols may appear  in internal-cruft.  (These  are the
          standardized ones; additional symbols may appear at the  discretion of
          the implementation.)

          cursorpos      This file (an output  tty) has the ability  to position
                         its cursor anywhere on the screen.

          rubout         This  file   (an  output   tty)  has   selective  erase
                         capability.  (cursorpos 'x) will work.

          sail           This  file  (an  output  tty)  has  the  so-called SAIL
                         character set.  This is an extension of ascii  which is
                         related but not eq to the SAIL character set.

ttyscan   (sstatus ttyscan func file) allows the user to supply a function which
          performs initial processing of  terminal input.  func is  a functional
          form, and  file must  be a  tty input file.   If it  is omitted,  t is
          assumed.  Both arguments are evaluated.

          When LISP wants  to take input from  file, it first calls  the prescan
          function, which is  supposed to gobble down  a complete unit  of input
          (for instance an S-expression)  and return a list of  characters.  The


September 8, 1977                   ∪3-1.8.1                           Page 3-77

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


          prescanner supplied  automatically by  LISP when a  tty input  file is
          first opened  counts parentheses and  does fancy rubout  processing on
          display terminals.  It  also implements the control-K,  control-L, and
          control-U characters which allow the complete input to  be redisplayed
          or cancelled, and takes care of force-feed characters.  A user-written
          prescanner   might  provide   additional  features   such   as  super-
          parentheses, name recognition and completion, or fancy editing.

          The prescan function func is applied to three arguments: the file, the
          name of the input function on whose behalf it is acting (read, readch,
          or readline), and a fixnum which, in the case of read, is the count of
          the number of unmatched left-parentheses.  It is supposed to  return a
          list  of fixnums,  which represent  characters.  The  prescan function
          should read the input with tyi, since it and tyipeek is the only input
          function which doesn't call the prescan.

          If the pre-scan function returns nil, an eof condition occurs  for the
          input file.  This is the standard way to signal over-rubout.

          There  is  a  function  called rubout  to  assist  the  pre-scanner in
          processing rubouts.  It is described on page .

          It is a good idea for the prescan function to lambda-bind echofiles to
          nil so that characters do not  appear in the echo files twice,  and so
          that the echo files reflect the "clean" input after rubout processing.

          (status ttyscan file) returns the file's func.

          This feature does not presently exist in the Multics implementation.

STATUS FUNCTIONS FOR THE OLD I/O SYSTEM

uread     (status uread) returns a 4-list for the current uread input source, or
          nil if uread is not being done.

          (sstatus uread --args--) is the same as (uread --args--)

uwrite    (status  uwrite)  returns the  2-list  for the  current  uwrite output
          destination.

          (sstatus uwrite --args--) is the same as (uwrite --args--)



Page 3-78                           ∪3-1.8.1                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


crunit    (status crunit) returns a 2-list of the current unit; i.e.  device and
          directory.

          (sstatus crunit device directory) sets the current default  device and
          directory for uread, etc.  The arguments are not evaluated.

crfile    (status crfile) returns a 2-list giving the file names for the current
          file in the "uread" I/O system.

          (sstatus crfile name1 name2)  sets the current default file  names for
          uread, etc.  The arguments are not evaluated.

STATUS FUNCTIONS FOR THE READER

   See section  13.6.2 for  a description  of how  the parameters  controlled by
these functions  are used.   Note: in  the following,  c represents  an argument
specifying a character.  If c is non-atomic it is evaluated, and the  value must
be a fixnum which is the ascii code  for a character.  If c is atomic it  is not
evaluated, and it may be a fixnum or a character object.

chtran    (status chtran c) gets  the character translation table entry  for the
          character c.  This is the ascii code of a character substituted  for c
          when it appears in a pname being read in.  This feature is used in the
          pdp-10 implementations to translate lower-case input to upper case.

          (sstatus chtran c k) sets  c's character translation to k.   k follows
          the  same rules  as c,  i.e. it  may be  a list  which evaluates  to a
          fixnum, or an unevaluated atom such as a fixnum or a character object.
          The value returned is k as a fixnum ascii code.

syntax    (status syntax c)  returns the syntax bits  for the character c,  as a
          fixnum.

          (sstatus syntax c m)  sets c's syntax bits  to m.  m is  evaluated and
          returned.  The setsyntax function is usually a better way to  do this,
          however.

          Note that in the above two sstatus calls, if c is a macro character it
          is changed back to its standard syntax and chtran before the requested
          operation is performed.  However, if in the standard readtable c  is a
          macro (i.e. ' and ;), instead of being changed to its  standard syntax
          and chtran its syntax  is set to 502 (slashified  extended alphabetic)
          and its chtran is set to itself.

September 8, 1977                   ∪3-1.8.1                           Page 3-79

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


macro     (status macro c) returns nil if c is not a macro character.  If c is a
          macro character it returns a list of the macro character  function and
          the type, which is nil for normal macros and s for splicing macros.

          (sstatus macro c f) makes c a macro character which calls the function
          f with no  arguments.  f is evaluated.   A fourth argument  to sstatus
          may be  supplied.  It  is not evaluated.   If it  is an  atomic symbol
          whose pname begins with s, c  is made a splicing macro.  If f  is nil,
          instead of  c being  made a macro-character,  c's macro  abilities are
          taken away  and c becomes  an ordinary  extended-alphabetic character.
          The setsyntax function is generally a better way to do this, however.

+         (status +) gets the value of the + switch (t or nil).  This  switch is
          normally nil.  If it is t, atomic symbols more than one character long
          beginning with a  + or a  - are interpreted  as numbers by  the reader
          even if  they contain  letters.  This  allows the  use of  input bases
          greater than ten.

          (sstatus + x) sets the + switch  to t or nil depending on x,  which is
          evaluated.  The new value of the + switch is returned.

ttyread   (status ttyread file) returns the value of the ttyread switch  for the
          file file.  If file is omitted  t is assumed.  At present this  is not
          used  for  anything  in the  Multics  implementation.   In  the pdp-10
          implementation  it controls  whether tty  "force feed"  characters are
          used.  See section 13.6.2 for details of force feed characters.

          (sstatus ttyread x file) sets the ttyread switch for file to t  or nil
          depending on x, which is  evaluated.  Again, file defaults to  t.  The
          new value of the switch is returned.

STATUS FUNCTIONS FOR THE PRINTER

terpri    (status terpri file) returns the value (t or nil) of the terpri switch
          for the file, which defaults  to t.  This switch is normally  nil.  If
          it is t, the  output functions such as  print and tyo will  not output
          any extra newlines when lines longer than linel are typed out.

          (sstatus terpri x file) sets the terpri switch.





Page 3-80                           ∪3-1.8.1                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


←         (status ← file) returns the value  (t or nil) of the ← switch  for the
          file, which  defaults to t.   If this  switch is t,  the ←  format for
          fixnums with lots of trailing zeroes is not used.

          (sstatus ← x file) sets the ← switch to the value of x, t or nil.

abbreviate(status  abbreviate) returns  the value  of the  abbreviation control.
          See section 13.7 for a description of the abbreviation control.

          (sstatus abbreviate n) sets the abbreviation control to n.

          (sstatus abbreviate nil) turns off abbreviation.

          (sstatus abbreviate t) turns on a maximal amount of abbreviation.

STATUS FUNCTION FOR THE GARBAGE COLLECTOR

gctime    (status  gctime) returns  the  number of  microseconds  spent garbage-
          collecting.

          (sstatus gctime  n) resets  the gctime  counter to  n and  returns the
          previous value of the gctime counter.

(status spcnames)  returns a  list of the names  of all the spaces  available in
          the LISP  being used.   These are  the names  acceptable to  the alloc
          function.

(status spcsize  space)  returns the  actual, current size  of space,  in words.
          space is evaluated.

(status pdlsize space)  returns the current number of words on a pdl.

(status pdlroom space)  returns the "pdlroom" of a pdl, i.e. the maximum size to
          which it may ever grow.

(status pdlmax space)  returns the current value of the "pdlmax" parameter  of a
          pdl.

(sstatus pdlmax  space size)   sets the pdlmax  parameter for  the pdl  space to
          size.  Both arguments are evaluated.




September 8, 1977                   ∪3-1.8.1                           Page 3-81

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


ENVIRONMENT ENQUIRIES

date      (status date) returns a  3-list indicating the current date  as (last-
          two-digits-of-the-year month-number day).

dow       (status dow) returns an atomic symbol which is the name of the current
          day of the week.

daytime   (status daytime) returns a 3-list of the 24-hour time of day  as (hour
          minute second).

time      (status time) is the same as (time), the number of seconds  the system
          has been up.

runtime   (status runtime) is the same as (runtime), the number  of microseconds
          of cpu time that have been used.

system    (status  system x)  returns a  list of  the system  properties  of the
          atomic  symbol x,  which is  evaluated.  This  list may  contain subr,
          fsubr, macro, or lsubr  if x is a  system function, and value  if this
          atomic symbol is a system variable.

uname     (status  uname) returns  an atomic  symbol whose  pname is  the user's
          login  name.  In  the  Multics implementation  this is  in  the format
          User.Project; the dot will be  slashified if print is used  to display
          this.  In  the TOPS-10  implementation this is  actually a  list (proj
          prog) rather than a symbol.

udir      (status udir) returns  the name of the  user's directory.  In  the ITS
          implementation this is the user's "master sname," which is usually the
          same as the user's name as returned by (status uname).  In the Multics
          implementation this is the  user's default working directory.   In the
          TOPS-10 implementation this is a list (proj prog).

lispversion
          (status lispversion) returns the version identification of lisp.  This
          is usually an atomic symbol.

jcl       (status  jcl) returns  the  "job command  line"  from DDT  in  the ITS
          implementation.  Only  the command part  (after altmode)  is returned.
          The initialization file name that precedes the altmode is  retained by
          LISP.   In  the  Multics implementation  this  returns  the explodec'd


Page 3-82                           ∪3-1.8.1                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


          second argument of the lisp  command, or else nil if the  lisp command
          did not have two arguments.  If lisp was invoked by

                        lisp environment←name "foo bar"

          then (status jcl) => (f o o /  b a r)

          This function is used by  subsystem implemented in MACLISP to  pick up
          the arguments from the command which invoked them.

   The following status functions only exist in the Multics implementation.

paging    (status paging)  returns a  list of the  paging-device page  reads and
          total page reads that have been caused by this process.

arg       (status  arg  n) returns  the  n+1'th argument  of  the  command which
          invoked  the  subsystem, as  an  interned atomic  symbol.   (The first
          argument,  (status arg  0),  is the  name  of the  subsystem.)  nil is
          returned if n is greater than the number of arguments to the command.

MISCELLANEOUS STATUS FUNCTIONS

evalhook  (sstatus evalhook t)  enables the evalhook feature;  (sstatus evalhook
          nil) disables it.  (status evalhook) returns the state of  the switch.
          See  for the details of this feature.

toplevel  (status  toplevel) returns  the top-level  form, which  is continually
          evaluated when LISP  is at its  top level.  If  this is nil,  a normal
          read-eval-print loop is used.

          (sstatus toplevel x)  evaluates and returns x  and sets the  top level
          form to this value.

          For example, to  make MACLISP have an  evalquote top level  similar to
          LISP 1.5:

               (sstatus toplevel
                        '(progn (print *)
                                (apply (read) (read)) ))

          See section 12.1 for further details.



September 8, 1977                   ∪3-1.8.1                           Page 3-83

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


breaklevel (status breaklevel) returns the break-loop form.  (sstatus breaklevel
          x) sets this form.  See  for how this is used.

uuolinks  (status  uuolinks) returns  a number  which represents  the  number of
          available slots for linking between compiled functions.

          (sstatus uuolinks) causes all  links between compiled functions  to be
          "unsnapped."  This should be done whenever (nouuo t) is done to insure
          that  the  interpreter  always   gets  a  chance  to   save  debugging
          information on every function call.

divov     (status divov) returns the state of the "divide overflow"  switch.  If
          this switch is nil an attempt  to divide by zero causes an  error.  If
          the switch is t the result of a division by zero is the numerator plus
          1.

          (sstatus divov x) sets the "divide overflow" switch to x.

          In the pdp-10 implementation, divov applies only to quotient.   // and
          //$ do not detect division by zero.

features  (status features) returns a list of symbols representing  the features
          implemented in the LISP being used.  The following symbols  may appear
          in this list:

               bibop         pdp-10 big-bag-of-pages memory management scheme

               lap           this LISP has a Lisp Assembly Program

               sort          the sorting functions  described in chapter  11 are
                              present

               edit          the  edit  function  described  in  chapter  18  is
                              present

               fasload       the  fasload facility  described in  chapter  14 is
                              present

               ↑f            the "moby I/O" facility is present

               bignum        the   arbitrary-precision  arithmetic   package  is
                              included in this LISP


Page 3-84                           ∪3-1.8.1                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


               strings       character  strings   and  the  functions   on  them
                              described in chapter 8 are present

               newio         the  I/O  functions  described  in  chapter  13 are
                              included  in this  LISP;  if this  feature  is not
                              present   only   some  of   those   functions  are
                              available.

               trace         the trace package (chapter 15) is present.

               grindef       the function  definition formatter (chapter  16) is
                              present.

               grind         the file formatter (chapter 16) is present.

               compiler      this is the LISP compiler (chapter 14)  rather than
                              the interpreter.

               fastarith     the  fast-arithmetic features  of the  compiler are
                              present

               ml            this LISP is on the MathLab machine at MIT

               ai            this LISP is on the AI machine at MIT

               H6180         this  LISP  is on  an  H6180 Multics  machine  or a
                              compatible machine such as a 68/60 or a 68/80.

               its           this LISP is on some ITS system

               Multics       this LISP is on some Multics system

               dec10         this LISP is on some DEC TOPS-10 system; or on some
                              TENEX system  since the TENEX  implementation runs
                              under a TOPS-10 emulator.

          A  package being  "present" means  that it  has been  loaded  into the
          environment.  If (status  features) claims it  is not present,  it may
          still  be  available  because  it  may  be  automatically  loaded when
          required.  This does not apply to the compiler.

          (car (last (status features))) is an implementation name, such  as its


September 8, 1977                   ∪3-1.8.1                           Page 3-85

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


          or dec10 or Multics.  The main idea behind this status call is that an
          application package can be loaded into any MACLISP  implementation and
          can decide what to do on the basis of the features it finds available.

feature   (status  feature  foo) is  roughly  equivalent to  (memq  'foo (status
          features)), i.e. it determines whether this LISP has  the foo-feature.
          Note that foo is not evaluated.

          (sstatus feature foo) makes foo a feature.  foo is not evaluated.  For
          example, the  trace package  does (sstatus feature  trace) when  it is
          loaded.

          Example:

             (cond ((status feature bignum)
                    (prog2 nil (eval (read)) (read)))  ;use first
                   (t (read) (eval (read)) ))          ;use second

             (defun factorial (n)    ;bignum version
                 (cond ((zerop n) 1)
                       ((times n (factorial (sub1 n))))
                   ))

             (defun factorial (n)    ;fixnum-only version
              (do () ((not (> n 13.)))  ;do until n <λ← 13.
                     (error "argument too big - factorial"
                            n
                            'wrng-type-arg))
                 (cond ((zerop n) 1)
                       ((* n (factorial (1- n)))) ))

nofeature (sstatus  nofeature foo)  makes  foo not  be  a feature.   foo  is not
          evaluated.

          (status nofeature foo) is equivalant to (not (status feature foo)).

status    (status status foo) returns t  if foo is a valid status  function.  If
          it is not, nil is returned.

          (status status) returns a  list of valid status functions.   The names
          are truncated to  some implementation-dependent number  of characters,
          such as 4 or 5.


Page 3-86                           ∪3-1.8.1                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


sstatus   (status sstatus foo) returns t if foo is a valid sstatus function.  If
          it is not, nil is returned.

          (status sstatus) returns a  list of valid sstatus functions.   As with
          (status  status),  the  names are  truncated  to  some implementation-
          dependent number of characters, such as 4 or 5.


1.8.2  Time


runtime             SUBR no args

          (runtime) returns as a fixnum  the number of microseconds of  cpu time
          used so far by the  process in which LISP is running.   The difference
          between two  values of (runtime)  indicates the amount  of computation
          that was done between the two calls to runtime.


time                SUBR no args

          (time) returns the time that the system has been up, in seconds. (As a
          flonum.)  The difference  between  the results  of two  calls  to time
          indicates   the   amount  of   elapsed   real  time.    (In   the  ITS
          implementation, time that elapses  while the system is stopped  due to
          memory errors is not considered "real" and not counted.)


sleep               SUBR 1 arg

          (sleep n) causes  a real-time delay of  n seconds, then returns  n.  n
          may be a fixnum or a flonum.


See also the alarmclock function, section 1.4.3, and the date, daytime,  and dow
functions of the status special form, described in the preceding section.


1.8.3  Escaping from Lisp


   It is possible to  escape temporarily from LISP  to execute a command  in the


September 8, 1977                   ∪3-1.8.1                           Page 3-87

**DRAFT**                   Maclisp Reference Manual                   **DRAFT**


host  operating system.   Of course,  the program  (or user)  that  supplies the
command has  to know which  operating system  it is running  under.  It  is also
possible for  LISP to  return permanently  to the  host operating  system.  This
discards the LISP environment and gives back whatever resources, such as memory,
it was using.
                         in the Multics implementation

cline               SUBR 1 arg

        (cline x), where x is a character string, executes the Multics command x
     and returns nil.  Example:
                              (cline "who -long")

quit                SUBR no args

        (quit) returns from the lisp command, freeing up the  temporary segments
     that were used to hold the LISP environment.


                           in the ITS implementation

valret              LSUBR 0 or 1 args

        (valret) is like (ioc  z); that is, it does  a .LOGOUT if LISP is  a top
     level procedure, and otherwise valrets ":VK " to DDT.

        (valret x) effectively performs an explodec on x (in practice x  is some
     strange  atomic symbol  like :PROCED/  :DISOWN/   , but  it may  be  any S-
     expression).  If the  string of characters is  one of "$↑X.", ":KILL  ", or
     ":KILL↑M"  then  valret performs  a  "silent kill"  by  executing  a .BREAK
     16,20000; otherwise valret performs  a .VALUE, giving the  character string
     to DDT to evaluate as commands.

        Examples:

        (valret ':PROCED/ :DISOWN/ )

        starts the LISP running on its own without a terminal.

        (valret '/ :KILL/ :TECO/↑M)

        kills the LISP and starts up a TECO.


Page 3-88                           ∪3-1.8.3                   September 8, 1977

**DRAFT**                          The System                          **DRAFT**


        (valret '0$N)

        causes DDT to print out the contents of all non-zero locations in LISP.


                         in the TOPS-10 implementation

        There is currently  no way for  LISP to return  a command string  to the
     Monitor  in  the  TOPS-10 implementation.   However,  (valret)  will return
     control to the monitor so that a command may be manually typed.   Then type
     CONTINUE to resume lisp.

































September 8, 1977                   ∪3-1.8.3                           Page 3-89
βββ